MyBatis

三层架构

三层架构包含的三层:

界面层(User Interface layer)、业务逻辑层(Business Logic Layer)、数据访问层(Data access layer) 三层的职责。
1、界面层(表示层,视图层):主要功能是接受用户的数据,显示请求的处理结果。使用 web 页面和 用户交互,手机 app 也就是表示层的,用户在 app 中操作,业务逻辑在服务器端处理。
2、业务逻辑层:接收表示传递过来的数据,检查数据,计算业务逻辑,调用数据访问层获取数据。
3、数据访问层:与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交 给业务层,同时将业务层处理的数据保存到数据库。

三层对应的包

界面层: controller包 (servlet)
业务逻辑层: service 包(XXXService类)
数据访问层: dao包(XXXDao类)

三层中类的交互

用户---> 界面层--->业务逻辑层--->数据访问层(持久层)-->DB数据库(mysql)
在这里插入图片描述

三层对应的处理框架

界面层---servlet---springmvc(框架)
业务逻辑层---service类--spring(框架)
数据访问层---dao类--mybatis(框架)

常见的 J2EE 中开发框架:
  • MyBatis 框架:
    MyBatis 是一个优秀的基于 java 的持久层框架,内部封装了 jdbc,开发者只需要关注 sql 语句 本身,而不需要处理加载驱动、创建连接、创建 statement、关闭连接,资源等繁杂的过程。
    MyBatis 通过 xml 或注解两种方式将要执行的各种 sql 语句配置起来,并通过 java 对象和 sql 的 动态参数进行映射生成最终执行的 sql 语句,最后由 mybatis 框架执行 sql 并将结果映射为 java 对象并返回。
  • Spring 框架:
    Spring 框架为了解决软件开发的复杂性而创建的。Spring 使用的是基本的 JavaBean 来完成以前 非常复杂的企业级开发。Spring 解决了业务对象,功能模块之间的耦合,不仅在 javase,web 中使用, 大部分 Java 应用都可以从 Spring 中受益。
    Spring 是一个轻量级控制反转(IoC)和面向切面(AOP)的容器。
  • SpringMVC 框架
    Spring MVC 属于 SpringFrameWork 3.0 版本加入的一个模块,为 Spring 框架提供了构建 Web 应用程序的能力。现在可以 Spring 框架提供的 SpringMVC 模块实现 web 应用开发,在 web 项目中 可以无缝使用 Spring 和 Spring MVC 框架。
为什么要使用三层?

1,结构清晰、耦合度低, 各层分工明确 2,可维护性高,可扩展性高
3,有利于标准化
4,开发人员可以只关注整个结构中的其中某一层的功能实现 5,有利于各层逻辑的复用

框架是什么?

框架是一个舞台,一个模版。
模版:
1、规定了好一些条款,内容。
2、加入自己的东西。
框架是一个模块
1、框架中定义好了一些功能。这些功能是可用的。
2、可以加入项目中自己的功能, 这些功能可以利用框架中写好的功能。
框架是一个软件,半成品的软件,定义好了一些基础功能, 需要加入你的功能就是完整的。
基础功能是可重复使用的,可升级的。
框架特点:
1、框架一般不是全能的, 不能做所有事情
2、框架是针对某一个领域有效。 特长在某一个方面,比如mybatis做数据库操作强,但是他不能做其它的。
3、框架是一个软件

  • 标准说法
    1、框架(Framework)是整个或部分系统的可重用设计,表现为一组抽象构件及构件实例间交互的方法;另一种认为,框架是可被应用开发者定制的应用骨架、模板。
    简单的说,框架其实是半成品软件,就是一组组件,供你使用完成你自己的系统。从另一个角度来说框架一个舞台,你在舞台上做表演。在框架基础上加入你要完成的功能。
    框架安全的,可复用的,不断升级的软件。
    2、框架要解决的最重要的一个问题是技术整合,在 J2EE 的 框架中,有着各种各样的技术,不同的应用,系统使用不同的技术解决问题。需要从 J2EE 中选择不同的技术,而技术自身的复杂性,有导致更 大的风险。企业在开发软件项目时,主要目的是解决业务问题。 即要求企业负责技术本身,又要求解 决业务问题。这是大多数企业不能完成的。框架把相关的技术融合在一起,企业开发可以集中在业务领 域方面。
    另一个方面可以提供开发的效率。

概述

一个框架,早期叫做 ibatis, 代码在 github。mybatis 是 MyBatis SQL Mapper Framework for Java(sql 映射框架)。
1、sql mapper:sql 映射
可以把数据库表中的一行数据 映射为 一个java对象。
一行数据可以看做是一个java对象。操作这个对象,就相当于操作表中的数据。
2、Data Access Objects(DAOs):数据访问 ,对数据库执行增删改查。

MyBatis 实现步骤及执行流程

MyBatis 实现步骤

1、新建的 student 表。
2、加入 maven 的 MyBatis 坐标,mysql 驱动的坐标。
3、创建实体类:student,保存表中的一行数据。
4、创建持久层的 dao 接口,定义操作数据库的方法。
5、创建一个 MyBatis 使用的配置文件,叫做 sql 映射文件。是用来写 sql 语句的。一般一个表一个 sql 映射文件。这个文件是 xml 文件。
在接口所在的目录中,文件名称和接口保持一致。
6、创建 MyBatis 的主配置文件:
一个项目就一个主配置文件。主配置文件提供了数据库的连接信息和 sql 映射文件的位置信息。
7、创建使用 MyBatis 类通过 mybatis 访问数据库。

执行流程

在这里插入图片描述

  • 1、读取 MyBatis 配置文件mybatis-config.xml
    mybatis-config.xml 作为 MyBatis 的全局配置文件,配置了 MyBatis 的运行环境等信息,其中主要内容是获取数据库连接。
  • 2、加载映射文件 Mapper.xml
    Mapper.xml 文件即 SQL 映射文件(如下面例子中的 Student.xml),该文件中配置了操作数据库的 SQL 语句,需要在 mybatis-config.xml 中加载才能执行。mybatis-config.xml 可以加载多个配置文件,每个配置文件对应数据库中的一张表。
  • 3、构建会话工厂
    通过 MyBatis 的环境等配置信息构建会话工厂 SqlSessionFactory。
  • 4、创建 SqlSession 对象。
    由会话工厂创建 SqISession 对象,该对象中包含了执行 SQL 的所有方法。
  • 5、Executor 接口
    MyBatis 底层定义了一个 Executor 接口来操作数据库,它会根据 SqISession 传递的参数动态地生成需要执行的SQL语句,同时负责查询缓存的维护。
  • 6、MappedStatement
    在 Executor 接口的执行方法中,包含一个 MappedStatement 类型的参数,该参数是对映射信息的封装,用于存储要映射的 SQL 语句的 id、参数等。Mapper.xml 文件中一个 SQL 对应一个 MappedStatement 对象,SQL 的 id 即是 MappedStatement 的 id。
  • 7、输入参数映射。
    在执行方法时,MappedStatement 对象会对用户执行 SQL 语句的输入参数进行定义(可以定义为 Map、List类型、基本类型和 POJO 类型),Executor 执行器会通过 MappedStatement 对象在执行 SQL 前,将输入的 Java 对象映射到 SQL 语句中。这里对输入参数的映射过程就类似于 JDBC 编程中对 PreparedStatement 对象设置参数的过程。
  • 8、输出结果映射。
    在数据库中执行完 SQL 语句后,MappedStatement 对象会对 SQL 执行输出的结果进行定义(可以定义为 Map 和 List 类型、基本类型、POJO 类型),Executor 执行器会通过 MappedStatement 对象在执行 SQL 语句后,将输出结果映射至 Java 对象中。这种将输出结果映射到 Java 对象的过程就类似于 JDBC 编程中对结果的解析处理过程。
配置日志功能

在 mybatis-config.xml 文件加入日志配置,可以在控制台输出执行的 sql 语句和参数

<!--settings:控制 Mybatis 全局行为-->
<settings>
	<!--配置日志功能-->
	<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
代码示例

防止找不到 xml 文件和 properties 文件
在这里插入图片描述
Student.java

package com.yu.domain;

public class Student {

    private Integer id;
    private String name;
    private String email;
    private Integer age;

	//有参、get、set、toString
}

StudentDao.java

package com.yu.dao;

import com.yu.domain.Student;
import java.util.List;

public interface StudentDao {

    //查询 Student 表中的所有数据
    public List<Student> selectStudent();
}

mybatis-config.xml

<?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">
<!--mybatis 的主配置文件,主要定义了数据库的配置信息,sql映射文件的位置。-->
<!--configuration:根标签-->
<configuration>
    <!--settings:控制 Mybatis 全局行为-->
    <settings>
        <!--配置日志功能-->
        <setting name="logImpl" value="STDOUT_LOGGING" />
    </settings>
    <!--环境配置:数据库的连接信息。-->
    <environments default="mydev">
        <!--id:数据源的名称(自定义,具有唯一性)-->
        <environment id="mydev">
            <!--配置事务类型:使用JDBC事务(使用Connection的提交和回滚)-->
            <transactionManager type="JDBC"/>
            <!--
            数据源  dataSource:创建数据库Connection对象。
            type: POOLED(表示使用数据库的连接池)
            -->
            <dataSource type="POOLED">
                <!--连接数据库的四个要素-->
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="?"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <!--
        告诉mybatis要执行的sql语句的位置。
        一个mapper标签指定一个文件的位置。
        从类路径(target/clasess)开始的路径信息。
        -->
        <mapper resource="java/com/yu/dao/StudentDao.xml"/>
        <!--可能还有多个
        <mapper resource="com/yu/dao/StudentDao.xml"/>
        -->
    </mappers>
</configuration>

<mapper resource="java/com/yu/dao/StudentDao.xml"/>对应编译后的包路径:
在这里插入图片描述
StudentDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--
指定约束文件,其中 mybatis-3-mapper.dtd是约束文件名称,扩展名叫 dtd。
约束文件作用:限制,检查在当前文件中出现的标签,属性必须符合 mybatis 的要求。
-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--
mapper 是当前文件的根标签,是必须的。
namespace:叫做命名空间,必须有值,自定义的唯一字符串。
可以是自定义的字符串,但建议使用 dao 接口的全限定名称。
-->
<mapper namespace="com.yu.dao.StudentDao">
    <!--
    <select>:查询数据,标签中必须是 select 语句。
    id:sql语句的自定义名称,mybatis 会使用这个 id 的值来找到要执行的 sql 语句,
    推荐使用 dao 接口中方法名称,使用名称来表示要执行的 sql 语句。
    resultType:查询语句的返回结果数据类型,使用全限定类名。
    -->
    <select id="selectStudent" resultType="com.yu.domain.Student">
        <!--要执行的  sql语句-->
        select id,name,email,age from student
    </select>
    <!--
    在当前文件中,可以使用特定的标签,表示数据库的特定操作。
    <select>:表示执行查询,放的是 select 语句。
    <update>:表示更新数据库的操作,放的是 update 语句。
    <insert):表示插入,放的是 insert 语句。
    <delete>:表示删除,执行的 delete 语句。
    -->
</mapper>

MyApp.java

package com.yu;

import com.yu.domain.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 java.io.IOException;
import java.io.InputStream;
import java.util.List;

public class MyApp {
    public static void main(String[] args) throws IOException {
        //访问mybatis读取student数据
        //1、定义mybatis主配置文件的名称,从类路径的根开始(target/clasess)
        String config = "resources/mybatis-config.xml";
        //2、读取这个config表示的文件
        InputStream is = Resources.getResourceAsStream(config);
        //3、创建SqlSessionFactoryBuilder对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //4、创建SqlSessionFactory对象
        SqlSessionFactory factory = builder.build(is);
        //5、【重要】获取SqlSession对象,从sqlSessionFactory中获取sqlSession
        SqlSession sqlSession = factory.openSession();
        //6、【重要】指定要执行的sql语句的标识:sql映射文件中的namespake + "." +标签的id值
        String sqlId = "com.yu.dao.StudentDao" + "." + "selectStudent";
        //7、执行sql语句,通过sqlId找到语句
        List<Student> studentList = sqlSession.selectList(sqlId);
        //8、输出结果
        studentList.forEach(student -> System.out.println(student));
        //9、关闭SqlSession对象
        sqlSession.close();
    }
}

在这里插入图片描述

代码示例(插入数据)

在 StudentDao.xml 的 mapper 标签中加上:

    <!--插入数据-->
    <insert id="insertStudent">
        insert into student values(#{id},#{name },#{email},#{age})
    </insert>

使用 Junit 进行测试:

package com.yu;

import com.yu.domain.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 TestInsert {
    @Test
    public void insertvalues() throws IOException {

        String config = "resources/mybatis-config.xml";
        InputStream is = Resources.getResourceAsStream(config);
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(is);
        SqlSession sqlSession = factory.openSession();
        String sqlId = "com.yu.dao.StudentDao.insertStudent";
        int result = sqlSession.insert(sqlId,new Student(3,"wangwu","ww@qq.com",24));
        //Mybatis 默认不是自动提交事务的,所以在 insert、update、delete 后要手工提交事务
        sqlSession.commit();
        sqlSession.close();
        System.out.println(result);
    }
}

日志:
在这里插入图片描述
数据库:
在这里插入图片描述
进行增删改操作时需要手动提交事务。

	//Mybatis 默认不是自动提交事务的,所以在 insert、update、delete 后要手工提交事务
	sqlSession.commit();

但是使用openSession(true);方法可以创建一个自动提交事务的 SqlSession 对象:

SqlSession sqlSession = factory.openSession();

MyBatis 工具类

在上面的示例中每个方法执行时都需要读取配置文件,并根据配置文件的信息构建 SqlSessionFactory 对象,然后创建 SqlSession 对象,这导致了大量的重复代码。为了简化开发,可以将上述重复代码封装到一个工具类中,然后通过工具类来创建 SqISession。

package com.yu.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;

/**
 * MyBatis工具类
 */
public class MyBatisUtils {
    private static SqlSessionFactory sqlSessionFactory = null;

    //初始化 SqlSessionFactory 对象
    static {
        try {
            //使用 MyBatis 提供的 Resources 类加载 MyBatis 的配置文件
            String resource = "mybatis-config.xml";
            InputStream is = Resources.getResourceAsStream(resource);
            //构建 sqlSessionFactory 工厂
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //获取 SqlSession 对象的静态方法
    public static SqlSession getSqlSession() {
        SqlSession sqlSession = null;
        if (sqlSessionFactory != null) {
            sqlSession = sqlSessionFactory.openSession();
        }
        return sqlSession;
        //也可以直接这样
        //return sqlSessionFactory.openSession();
    }
}

这样,在使用时就只创建了一个 SqlSessionFactory 对象,并且可以通过工具类的 getSession() 方法来获取 SqlSession 对象。

示例

使用工具类将上面的 TestInsert 修改一下:

package com.yu;

import com.yu.domain.Student;
import com.yu.utils.MyBatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.io.IOException;

public class TestInsert {
    @Test
    public void insertvalues() throws IOException {
        
        //使用工具类
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        
        String sqlId = "com.yu.dao.StudentDao.insertStudent";
        int result = sqlSession.insert(sqlId,new Student(3,"wangwu","ww@qq.com",24));
        sqlSession.commit();
        sqlSession.close();
        System.out.println(result);
    }
}

MyBatis 提供的功能

1、提供了创建 Connection,Statement,ResultSet 的能力,不用开发人员创建这些对象了。
2、提供了执行 sql 语句的能力,不用你执行 sql。
3、提供了循环 sql,把 sql 的结果转为 java 对象,List 集合的能力。

while (rs.next()) {
	Student stu = new Student();
	stu.setId(rs.getInt("id"));
	stu.setName(rs.getString("name"));
	stu.setAge(rs.getInt("age"));
	//从数据库取出数据转为 Student 对象,封装到 List 集合
	stuList.add(stu);
}

4、提供了关闭资源的能力,不用你关闭 Connection,Statement,ResultSet。
开发人员做的是: 提供 sql 语句
最后是:开发人员提供 sql 语句---mybatis 处理 sql---开发人员得到 List 集合或 java 对象(表中的数据)

  • 总结:
    mybatis 是一个 sql 映射框架,提供的数据库的操作能力。增强的 JDBC,使用 mybatis 让开发人员集中精神写 sql 就可以了,不必关心 Connection,Statement,ResultSet 的创建,销毁,sql 的执行。

MyBatis 核心对象

1、Resources: mybatis中的一个类, 负责读取主配置文件
InputStream in = Resources.getResourceAsStream("mybatis.xml");
2、SqlSessionFactoryBuilder : 创建SqlSessionFactory对象,
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
//创建SqlSessionFactory对象
SqlSessionFactory factory = builder.build(in);
3、SqlSessionFactory : 重量级对象, 程序创建一个对象耗时比较长,使用资源比较多。
在整个项目中,有一个就够用了。
SqlSessionFactory:接口 , 接口实现类: DefaultSqlSessionFactory
SqlSessionFactory作用: 获取SqlSession对象。SqlSession sqlSession = factory.openSession();

  • openSession()方法说明:
    1、openSession() :无参数的, 获取是非自动提交事务的SqlSession对象
    2、openSession(boolean): openSession(true) 获取自动提交事务的SqlSession.
    3、openSession(false) 非自动提交事务的SqlSession对象
    4、SqlSession:
    SqlSession接口 :定义了操作数据的方法 例如 selectOne() ,selectList() ,insert(),update(), delete(), commit(), rollback()
    SqlSession接口的实现类DefaultSqlSession。
    使用要求: SqlSession对象不是线程安全的,需要在方法内部使用, 在执行sql语句之前,使用openSession()获取SqlSession对象。
    在执行完sql语句后,需要关闭它,执行SqlSession.close(). 这样能保证他的使用是线程安全的。

MyBatis 动态代理

1、动态代理:使用SqlSession.getMapper(dao接口.class) 获取这个dao接口的对象
2、传入参数:从java代码中把数据传入到mapper文件的sql语句中。

        //使用工具类
        SqlSession sqlSession = MyBatisUtils.getSqlSession();
        /*
        * 使用MyBatis的动态代理机制,使用SqlSession.getMapper(dao接口)。
        * getMapper能获取dao接口对应的实现类对象。
        * */
        StudentDao dao = sqlSession.getMapper(StudentDao.class);
        List<Student> student = dao.selectStudent();
        student.forEach(System.out::println);
        sqlSession.close();
  • 使用动态代理要求
    对应的 StudentDao.xml 里面的如下参数一一对应:
    在这里插入图片描述
    1、dao 接口和 mapper 文件放在一起,同一个目录。
    2、dao 接口和 mapper 文件名称一致。
    3、mappers + nameSpace的值是dao接口的全限定名称。
    4、mapper 文件中的 <select>、<insert>、<update>、<delete>等 id 都是接口中方法名称。
    5、dao 接口中不要使用重载方法,不要使用同名、不同参数的方法。

MyBatis 参数

从 java 代码中把参数传递到 mapper.xml 文件

parameterType

1、写在 mapper 文件中的 一个属性,表示 dao 接口中方法的参数的数据类型。
2、parameterType 的值是 java 的数据类型全限定名称或者是 MyBatis 定义的别名(详见 MyBatis 文档)。
例如:

parameterType="java.lang.Integer"
或
parameterType="int"

3、注意:
parameterType 不是强制的,MyBatis 通过反射机制能够发现接口参数的数类型。所以可以没有,一般也不写。

一个简单类型的参数:

1、简单类型:MyBatis 把 java 的基本数据类型和 String 都叫简单类型。
2、在 mapper 文件获取简单类型的一个参数的值,使用#{任意字符}
3、例子:
接口:

public Student  selectStudentById(Integer id)

mapper:

select id, name, email, age from student where id = #{studentId}
多个参数,使用 @Param 命名参数

1、当 Dao 接口方法多个参数,需要通过名称使用参数。在方法形参前面加入:
@Param(“自定义参数名”)
mapper 文件使用:
#{自定义参数名}
2、例如定义:

List<Student> selectStudent( @Param(“personName”)    String name ) { … }

mapper 文件:

select * from student where name = #{ personName}

接口方法:

List<Student> selectMultiParam(@Param("personName") String name,
								@Param("personAge") int age);

mapper 文件:

<select id="selectMultiParam" resultType="com.yu.domain.Student">
select id, name, email, age from student where name = #{personName} or age = #{personAge}
</select>

测试方法:

@Test
public void testSelectMultiParam(){
List<Student> stuList = studentDao.selectMultiParam("赵六", 20);
stuList.forEach( stu -> System.out.println(stu));
}
多个参数,使用 java 对象

1、使用 java 对象传递参数,java 的属性值就是 sql 需要的参数值。每一个属性就是一个参数。
语法格式:
#{property, javaType = java中数据类型名, jdbcType = 数据类型名称}
javaType:指 java 中的属性数据类型。jdbcType:在数据库中的数据类型。
(但是这种方式很少用,因为 javaType, jdbcType 的值 MyBatis 反射能获取,不用提供。)
2、javaType, jdbcType 的类型 MyBatis 可以检测出来,一般不需要设置。
常用格式:
#{property}
(jdbcType 详见 mybatis-3.5.1.pdf 第 43 页 4.1.5.4 小节)
在这里插入图片描述
创建保存参数值的对象 QueryParam

public class QueryParam {
	private String queryName;
	private int queryAge;
	//set,get 方法
}

接口方法:

List<Student> selectMultiObject (QueryParam queryParam);

mapper 文件:

<select id="selectMultiObject" resultType="com.yu.domain.Student">
select id, name, email, age from student where name = #{queryName} or age = #{queryAge}
</select>

<select id="selectMultiObject" resultType="com.yu.domain.Student">
select id, name, email, age from student where 
name = #{queryName, javaType=string, jdbcType=VARCHAR} 
or 
age = #{queryAge, javaType=int, jdbcType=INTEGER}
</select>

测试方法:

@Test
public void selectMultiObject() {
	QueryParam qp  = new QueryParam();
	qp.setQueryName("艾迪");
	qp.setQueryAge(22);
	List<Student> stuList = studentDao.selectMultiObject(qp);
	stuList.forEach( stu -> System.out.println(stu));
}
多个参数,按位置

1、参数位置从0开始,引用参数语法:
#{ arg 位置 }
2、第一个参数是#{arg0},第二个是#{arg1}
3、注意:mybatis-3.3 版本和之前的版本使用#{0}, #{1}方式,从 mybatis3.4 开始使用#{arg0}方式。
接口方法:

List<Student> selectByNameAndAge(String name, int age);

mapper 文件:

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

测试方法:

@Test
public void testSelectByNameAndAge(){ //按位置参数
	List<Student> stuList = student;
	Dao.selectByNameAndAge("李力",20);
	stuList.forEach( stu -> System.out.println(stu));
}
多个参数,使用 Map

1、Map 集合可以存储多个值,使用 Map 向 mapper 文件一次传入多个参数。Map 集合使用 String 的 key,Object 类型的值存储参数。mapper 文件使用 #{key} 引用参数值。

  • 例如
Map<String,Object> data = new HashMap<String,Object>();
data.put(“myname”,”李力”);
data.put(“myage”,20);

接口方法:

List<Student> selectMultiMap(Map<String, Object> map);

mapper 文件:

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

测试方法:

@Test
public void testSelectMultiMap(){
	Map<String,Object> data = new HashMap<>();
	data.put("myname", "李力");// #{myname}
	data.put("myage",20);// #{myage}
	List<Student> stuList = studentDao.selectMultiMap(data);
	stuList.forEach( stu -> System.out.println(stu));
}

VO

VO:
Value Object,放一些存储数据的类。比如说提交请求参数,name, age,现在想把 name, age 传给一个 service 类。
VO:
View Object,从 servlet 把数据返回给浏览器使用的类,表示显示结果的类。
POJO:
普通的有 set, get 方法的 java 类。普通的java对象。
Servlet:
StudentService( addStudent( MyParam param) )
entity(domain域):
实体类,和数据库中的表对应的类。
java的(PO,VO,TO,BO,DAO,POJO)解释

# 和 $

#:占位符

1、告诉 MyBatis 使用实际的参数值代替。并使用 PrepareStatement 对象执行 sql 语句,#{…}代替 sql 语句的 “?”。这样做更安全,更迅速,通常也是首选做法。
2、例:
mapper 文件

<select id="selectById" resultType="com.yu.domain.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,1005);

解释:
where id = ? 就是 where id = #{studentId};ps.setInt(1, 1005),1005 会替换掉 #{studentId}。

$:字符串替换

1、表示拼接 SQL 的字符串,即不加解释的原样输出,${value}表示的是拼接简单类型参数。
2、告诉 MyBatis 使用$包含的“字符串”替换所在位置。使用 Statement 把 sql 语句和${}的 内容连接起来。主要用在替换表名,列名,不同列排序等操作。

  • 例①:分别使用 id,email 列查询

Student 接口方法:

Student findById(int id);
Student findByEmail(String email);

mapper 文件:

<select id="findById" resultType="com.yu.domain.Student">
	select * from student where id = #{studentId}
</select>
<select id="findByEmail" resultType="com.yu.domain.Student">
	select * from student where email = #{stuentEmail}
</select>

测试方法:

@Test
public void testFindStuent(){
	Student student1 = studentDao.findById(1002);
	System.out.println("findById:"+student1);
	Student student2 = studentDao.findByEmail("zhou@126.net");
	System.out.println("findByEmail:"+student2);
}
  • 例②:通用方法,使用不同列作为查询条件。

接口方法:

Student findByDiffField(@Param("col") String colunName, @Param("cval") Object value);

mapper 文件:

<select id="findByDiffField"  resultType="com.yu.domain.Student">
	select * from student where ${col} = #{cval}
</select>

测试方法:

@Test
public void testFindDiffField(){
	Student student1 = studentDao.findByDiffField("id",1002);
	System.out.println("按 id 列查询:"+student1);
	Student student2 = studentDao.findByDiffField("email","zhou@qq.com");
	System.out.println("按 email 列查询:"+student2);
}
使用 $ 既实现模糊查询,又防止 SQL 注入

在使用 $ 进行 SQL 字符串拼接时,无法防止 SQL 注入问题。所以想要既能实现模糊查询,又要防止 SQL 注入,就可以使用 MySQL 中的 concat() 函数进行字符串拼接。
示例:

select * from customer where username like concat('%', #(value), '%')
解释

1、
select id, name, email, age from student where id = #{studentId}

的结果:select id, name, email, age from student where id = ?

2、
select id, name, email, age from student where id = \({studentId} \) 的结果:select id, name, email, age from student where id =1001
相当于:
String sql="select id,name, email,age from student where id=" + "1001";
3、
使用的 Statement 对象执行 sql, 效率比 PreparedStatement 低。
$ 可以替换表名或者列名, 前提是能确定数据是安全的。可以使用 $。

# 和 $ 区别

1、#使用 ? 在 sql 语句中做站位的,使用 PreparedStatement 执行 sql,效率高。
2、#能够避免 sql 注入,更安全。
3、$ 不使用占位符,是字符串连接方式,使用 Statement 对象执行 sql,效率低。
4、$ 有 sql 注入的风险,缺乏安全性。
5、$ 可以替换表名或者列名。

封装 MyBatis 输出结果

resultType

1、指 sql 语句执行完毕后,数据转为 java 对象, java类型是任意的。
2、执行 sql 得到 ResultSet 转换的类型,使用类型的完全限定名或别名。(例如 java.lang.Integer 别名是 int)
3、注意如果返回的是集合,那应该设置为集合包含的类型,而不是集合本身
4、resultType 和 resultMap,不能同时使用。

  • 处理方式:
    1、MyBatis 执行 sql 语句, 然后 MyBatis 调用类的无参数构造方法,创建对象。
    2、MyBatis 把 ResultSet 指定列值赋给同名的属性。
    在这里插入图片描述
  • 定义自定义类型的别名(建议使用全限定名称,保证唯一性)
    1、在 MyBatis 主配置文件中定义,使<typeAlias>定义别名。
    2、可以在 resultType 中使用自定义别名。
    在这里插入图片描述
    第一种:
    在这里插入图片描述
    第二种:
    在这里插入图片描述
    如果在实体类加了注解的话,注解的值就是别名:
@Alias(value = "student")
public class Student {
	id;
	name;
	//get、set、toString...
}
  • 简单类型
    接口方法:
int countStudent();

mapper 文件:

<select id="countStudent" resultType="int">
	select count(*) from student
</select>

测试方法:

@Test
public void testRetunInt(){
	int count = studentDao.countStudent();
	System.out.println("学生总人数:"+ count);
}
  • 对象类型
    接口方法:
Student selectById(int id);

mapper 文件:

<select id="selectById" resultType="com.yu.domain.Student">
	select id,name,email,age from student where id=#{studentId}
</select>

框架的处理:
使用构造方法创建对象。调用 setXXX 给属性赋值。

Student student = new Student();
sql 语句列 java 对象方法 -
id setId( rs.getInt(“id”) ) 调用列名对应的 set 方法;id 列:setId();name 列:setName()
name setName( rs.getString(“name”) ) -
email setEmail( rs.getString(“email”) ) -
age setAge( rs.getInt(“age”) ) -
注意:Dao 接口方法返回是集合类型,需要指定集合中的类型,不是集合本身。
在这里插入图片描述
  • Map
    1、sql 的查询结果作为 Map 的 key 和 value。推荐使用 Map<Object, Object>。
    2、注意:Map 作为接口返回值,sql 语句的查询结果最多只能有一条记录。大于一条记录是错误。
    接口方法:
Map<Object,Object> selectReturnMap(int id);

mapper 文件:

<select id="selectReturnMap" resultType="java.util.HashMap">
	select name, email from student where id = #{studentId}
</select>

测试方法:

@Test
public void testReturnMap(){
	Map<Object, Object> retMap = studentDao.selectReturnMap(1002);
	System.out.println("查询结果是 Map:"+retMap);
}
resultMap

1、resultMap 可以自定义 sql 的结果和 java 对象属性的映射关系。更灵活的把列值赋值给指定属性。 常用在列名和 java 对象属性名不一样的情况
2、使用方式:
先定义 resultMap,指定列名和属性的对应关系。再在<select>中把 resultType 替换为 resultMap。

  • 结果映射
    指定列名和java对象的属性对应关系。
    1、自定义列值赋值给哪个属性。
    2、当列名和属性名不一样时,一定使用 resultMap。
    接口方法:
List<Student> selectUseResultMap(QueryParam param);

mapper文件:

<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用;
type:期望转为的 java 对象的全限定名称或别名。
-->
<resultMap id="studentMap" type="com.yu.domain.Student">
	<!-- 主键字段使用 id -->
	<id column="id" property="id" />
	<!--非主键字段使用 result-->
	<result column="name" property="name"/>
	<result column="email" property="email" />
	<result column="age" property="age" />
</resultMap>
<!--resultMap: resultMap标签中的 id属性值-->
<select id="selectUseResultMap" resultMap="studentMap">
	select id, name, email, age from student where name = #{queryName} or age = #{queryAge}
</select>

测试方法:

@Test
public void testSelectUseResultMap() {
	QueryParam param = new QueryParam();
	param.setQueryName("lili");
	param.setQueryAge(20);
	List<Student> stuList = studentDao.selectUseResultMap(param);
	stuList.forEach( stu -> System.out.println(stu));
}
实体类属性名和列名不同的处理方式
  • 使用列别名和<resultType>
    步骤:
    1、创建新的实体类 PrimaryStudent
package com.yu.domain;
public class PrimaryStudent {
	private Integer stuId;
	private String stuName;
	private Integer stuAge;
	// set, get方法
}

2、接口方法

List<PrimaryStudent> selectUseFieldAlias(QueryParam param);

3、mapper 文件:

<select id="selectUseFieldAlias" resultType="com.yu.domain.PrimaryStudent">
	select id as stuId, name as stuName, age as stuAge
	from student where name = #{queryName} or age = #{queryAge}
</select>

4.测试方法

@Test
public void testSelectUseFieldAlias() {
	QueryParam param = new QueryParam();
	param.setQueryName("mike");
	param.setQueryAge(20);
	List<PrimaryStudent> stuList;
	stuList = studentDao.selectUseFieldAlias(param);
	stuList.forEach( stu -> System.out.println(stu));
}
  • 使用<resultMap>
    步骤:
    1、接口方法
List<PrimaryStudent> selectUseDiffResultMap(QueryParam param);

2、mapper 文件:

<!-- 创建 resultMap
id:自定义的唯一名称,在<select>使用;
type:期望转为的 java 对象的全限定名称或别名。
-->
<resultMap id="primaryStudentMap" type="com.yu.domain.PrimaryStudent">
	<!-- 主键字段使用 id -->
	<id column="id" property="stuId" />
	<!--非主键字段使用 result-->
	<result column="name" property="stuName"/>
	<result column="age" property="stuAge" />
</resultMap>
<!--resultMap: resultMap 标签中的 id 属性值-->
<select id="selectUseDiffResultMap" resultMap="primaryStudentMap">
	select id, name, email, age from student
	where name = #{queryName} or age = #{queryAge}
</select>

3、测试方法

@Test
public void testSelectUseDiffResultMap() {
	QueryParam param = new QueryParam();
	param.setQueryName("mike");
	param.setQueryAge(20);
	List<PrimaryStudent> stuList;
	stuList = studentDao.selectUseDiffResultMap(param);
	stuList.forEach( stu -> System.out.println(stu));
}

模糊查询 like

  • 模糊查询的实现有两种方式:
    一是在 java 代码中给查询数据加上“%”;
    二是在 mapper 文件 sql 语句的条件位置加上“%”。
需求:查询姓名有“三”的
  • 例1:java 代码中提供要查询的 “%三%”
    接口方法:
List<Student> selectLikeFirst(String name);

mapper 文件:

<select id="selectLikeFirst" resultType="com.yu.domain.Student">
	select id,name,email,age from student
	where name like #{studentName}
</select>

测试方法:

@Test
public void testSelectLikeOne() {
	String name="%三%";
	List<Student> stuList = studentDao.selectLikeFirst(name);
	stuList.forEach( stu -> System.out.println(stu));
}
  • 例 2:mapper文件中使用 like name "%" #{xxx} "%"
    接口方法:
List<Student> selectLikeSecond(String name);

mapper 文件:

<select id="selectLikeSecond" resultType="com.yu.domain.Student">
	select id, name, email, age from student
	where name like "%" #{studentName} "%"
</select>

测试方法:

@Test
public void testSelectLikeSecond() {
	String name="三";
	List<Student> stuList = studentDao.selectLikeSecond(name);
	stuList.forEach( stu -> System.out.println(stu));
}
  • 也可以像上面一样使用 MySQL 中的 concat() 函数进行字符串拼接。

动态sql

概述

1、动态 SQL,SQL 的内容是变化的,可以根据条件获取到不同的 SQL 语句。主要是 where 部分发生变化。
2、通过 MyBatis 提供的各种标签对条件作出判断以实现动态拼接 SQL 语句。这里的条件判断使用的表达式为 OGNL 表达式。
3、动态 SQL 的实现,使用的是mybatis提供的标签,常用的动态 SQL 标签有<if>、<where>、<choose/>、<foreach>等。 MyBatis 的动态 SQL 语句,与 JSTL 中的语句非常相似。
4、动态 SQL,主要用于解决查询条件不确定的情况:在程序运行期间,根据用户提交的查询条件进行查询。提交的查询条件不同,执行的 SQL 语句不同。若将每种可能的情况均逐一列出,对所有条件进行排列组合,将会出现大量的 SQL 语句。此时,可使用动态 SQL 来解决这样的问题。

  • 注意
    在 mapper 的动态 SQL 中若出现大于号(>)、小于号(<)、大于等于号(>=),小于等于号(<=)等 符号,最好将其转换为实体符号。否则,XML 可能会出现解析出错问题。
    特别是对于小于号(<),在 XML 中是绝不能出现的。否则解析 mapper 文件会出错。
    实体符号表:
< 小于 &lt;
> 大于 &gt;
>= 大于等于 &gt;=
<= 小于等于 &lt;=
动态 SQL 之<if>

对于该标签的执行,当 test 的值为 true 时,会将其包含的 SQL 片断拼接到其所在的 SQL 语句中。 语法:

<if test="(条件)判断java对象的属性值">
	部分sql语句
</if>

接口方法:

List<Student> selectStudentIf(Student student);

mapper 文件:

<select id="selectStudentIf" resultType="com.yu.domain.Student">
	select id, name, email, age from student
	where 1 = 1
	<if test="name != null and name !='' ">
		and name = #{name}
	</if>
	<if test="age > 0 ">
		and age &gt; #{age}
	</if>
</select>

测试方法:

@Test
public void testSelect() throws IOException {
	Student param = new Student();
	param.setName("Tom");
	param.setAge(18);
	List<Student> studentList = studentDao.selectStudentIf(param);
	studentList.forEach( stu -> System.out.println(stu));
}
动态 SQL 之<where>

1、<where>用来包含多个<if>的, 当多个 if 有一个成立的,<where>会自动增加一个 where 关键字,并去掉 if 中多余的 and,or 等。
2、<if/>标签的中存在一个比较麻烦的地方:需要在 where 后手工添加 1=1 的子句。因为,若 where 后的所有<if/>条件均为 false,而 where 后若又没有 1=1 子句,则 SQL
中就会只剩下一个空的 where,SQL出错。所以,在 where 后,需要添加永为真子句 1=1,以防止这种情况的发生。
3、但当数据量很大时,会严重影响查询效率。使用<where/>标签,在有查询条件时,可以自动添加上 where 子句;没有查询条件时,不会添加 where 子句。需要注意的是,第一个<if/>标签中的 SQL 片断,可以不包含 and。
4、不过,写上 and 也不错, 系统会将多出的 and 去掉。但其它<if/>中 SQL 片断的 and,必须要求写上。否则 SQL 语句将拼接出错。
5、语法:

<where>
	其他动态 sql
</where>

接口方法:

List<Student> selectStudentWhere(Student student);

mapper 文件:

<select id="selectStudentWhere" resultType="com.yu.domain.Student">
	select id, name, email, age from student
	<where>
		<if test="name != null and name !='' ">
			and name &gt; #{name}
		</if>
		<if test="age > 0 ">
			and age &gt; #{age}
		</if>
	</where>
</select>

测试方法:

@Test
public void testSelectWhere() throws IOException {
	Student param = new Student();
	param.setName("Alice");
	param.setAge(18);
	List<Student> studentList = studentDao.selectStudentWhere(param);
	studentList.forEach( stu -> System.out.println(stu));
}
动态 SQL 之<foreach>

1、<foreach/>标签用于实现对于数组与集合的遍历。
2、<foreach>是循环 java 中的数组,list集合的。主要用在 sql 的 in 语句中。如果用 java 代码来实现的话很麻烦。例如:
查找学生 id 是1001, 1002, 1003的三个学生。
在这里插入图片描述
在这里插入图片描述
3、<foreach>语法:

<foreach collection="集合类型" item="自定义变量" open="开始的字符" close="结束的字符" separator="分隔符">
	#{item的值}
</foreach>

标签说明:
collection:表示要遍历的集合类型, list ,array 等。
item:自定义的,表示数组和集合成员的变量。
以下三个标签 open、close、separator 为对遍历内容的 SQL 拼接:
open:循环开始时的字符。
close:循环结束时的字符。
separator:集合成员之间的分隔符。

  • 遍历 List<简单类型>
    表达式中的 List 使用 list 表示,其大小使用 list.size 表示。
    需求:查询学生 id 是1002, 1005, 1006 的。
    接口方法:
List<Student> selectStudentForList(List<Integer> idList);

mapper 文件:

<select id="selectStudentForList" resultType="com.yu.domain.Student">
	select id, name, email, age from student
	<if test="list !=null and list.size > 0 ">
		where id in
		<foreach collection="list" item="stuid" open="(" close=")" separator="," >
			#{stuid}
		</foreach>
	</if>
</select>

测试方法:

@Test
public void testSelectForList()  {
	List<Integer> list = new ArrayList<>();
	list.add(1002);
	list.add(1005);
	list.add(1006);
	List<Student> studentList = studentDao.selectStudentForList(list);
	studentList.forEach( stu -> System.out.println(stu));
}
  • 遍历 List<对象类型>
    接口方法:
List<Student> selectStudentForList2(List<Student> stuList);

mapper 文件:

<select id="selectStudentForList2" resultType="com.yu.domain.Student">
	select id,name,email,age from student
	<if test="list !=null and list.size > 0 ">
		where id in
		<foreach collection="list" item="stuobject" open="(" close=")" separator="," >
			#{stuobject.id}
		</foreach>
	</if>
</select>

测试方法:

@Test
public void testSelectForList2()  {
	List<Student> list = new ArrayList<>();
	Student s1 = new Student();
	s1.setId(1002);
	list.add(s1);
	
	s1 = new Student();
	s1.setId(1005);
	list.add(s1);
	
	List<Student> studentList = studentDao.selectStudentForList2(list);
	studentList.forEach( stu -> System.out.println(stu));
}
动态 SQL 之代码片段

1、sql代码片段, 就是复用一些语法
步骤:
先定义

<sql id="自定义名称唯一">
	sql语句,表名,字段等
</sql>

再使用

<include refid="id的值" />

2、<sql/>标签用于定义 SQL 片断,以便其它 SQL 标签复用。而其它标签使用该 SQL 片断,需要使用<include/>子标签。该<sql/>标签可以定义 SQL 语句中的任何部分,所以<include/>子标签可以放在动态 SQL 的任何位置。
接口方法:

List<Student> selectStudentSqlFragment(List<Student> stuList);

mapper 文件:

<!--创建 sql片段   id:片段的自定义名称-->
<sql id="studentSql">
	select id, name, email, age from student
</sql>
<select id="selectStudentSqlFragment" resultType="com.yu.domain.Student">
	<!-- 引用  sql片段   -->
	<include refid="studentSql"/>
	<if test="list !=null and list.size > 0 ">
		where id in
		<foreach collection="list" open="(" close=")" >
			#{stuobject.id}
		</foreach>
	</if>
</select>

测试方法:

@Test
public void testSelectSqlFragment()  {
	List<Student> list = new ArrayList<>();
	Student s1 = new Student();
	s1.setId(1002);
	list.add(s1);
	
	s1 = new Student();
	s1.setId(1005);
	list.add(s1);
	
	List<Student> studentList = studentDao.selectStudentSqlFragment(list);
	studentList.forEach( stu -> System.out.println(stu));
}

主配置文件

之前项目中使用的 mybatis-config.xml 是主配置文件。 主配置文件特点:
1、xml 文件,需要在头部使用约束文件

<?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">

2、根元素,<configuration>
3、主要包含内容:
定义别名、数据源、mapper 文件。

  • 关于settings
<!-- settings是 MyBatis 中全局的调整设置,它们会改变 MyBatis 的运行时行为,应谨慎设置 -->  
	    <settings>  
	        <!-- 该配置影响的所有映射器中配置的缓存的全局开关。默认值true -->  
	      <setting name="cacheEnabled" value="true"/>  
	      <!--延迟加载的全局开关。当开启时,所有关联对象都会延迟加载。 特定关联关系中可通过设置fetchType属性来覆盖该项的开关状态。默认值false  -->  
	      <setting name="lazyLoadingEnabled" value="true"/>  
	        <!-- 是否允许单一语句返回多结果集(需要兼容驱动)。 默认值true -->  
	      <setting name="multipleResultSetsEnabled" value="true"/>  
	      <!-- 使用列标签代替列名。不同的驱动在这方面会有不同的表现, 具体可参考相关驱动文档或通过测试这两种不同的模式来观察所用驱动的结果。默认值true -->  
	      <setting name="useColumnLabel" value="true"/>  
	      <!-- 允许 JDBC 支持自动生成主键,需要驱动兼容。 如果设置为 true 则这个设置强制使用自动生成主键,尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 默认值false  -->  
	      <setting name="useGeneratedKeys" value="false"/>  
	     <!--  指定 MyBatis 应如何自动映射列到字段或属性。 NONE 表示取消自动映射;PARTIAL 只会自动映射没有定义嵌套结果集映射的结果集。 FULL 会自动映射任意复杂的结果集(无论是否嵌套)。 -->   
	     <!-- 默认值PARTIAL -->  
	      <setting name="autoMappingBehavior" value="PARTIAL"/>  
	        
	      <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>  
	     <!--  配置默认的执行器。SIMPLE 就是普通的执行器;REUSE 执行器会重用预处理语句(prepared statements); BATCH 执行器将重用语句并执行批量更新。默认SIMPLE  -->  
	      <setting name="defaultExecutorType" value="SIMPLE"/>  
	      <!-- 设置超时时间,它决定驱动等待数据库响应的秒数。 -->  
	      <setting name="defaultStatementTimeout" value="25"/>  
	        
	      <setting name="defaultFetchSize" value="100"/>  
	      <!-- 允许在嵌套语句中使用分页(RowBounds)默认值False -->  
	      <setting name="safeRowBoundsEnabled" value="false"/>  
	      <!-- 是否开启自动驼峰命名规则(camel case)映射,即从经典数据库列名 A_COLUMN 到经典 Java 属性名 aColumn 的类似映射。  默认false -->  
	      <setting name="mapUnderscoreToCamelCase" value="false"/>  
	      <!-- MyBatis 利用本地缓存机制(Local Cache)防止循环引用(circular references)和加速重复嵌套查询。  
	             默认值为 SESSION,这种情况下会缓存一个会话中执行的所有查询。  
	            若设置值为 STATEMENT,本地会话仅用在语句执行上,对相同 SqlSession 的不同调用将不会共享数据。  -->  
	      <setting name="localCacheScope" value="SESSION"/>  
	      <!-- 当没有为参数提供特定的 JDBC 类型时,为空值指定 JDBC 类型。 某些驱动需要指定列的 JDBC 类型,多数情况直接用一般类型即可,比如 NULL、VARCHAR 或 OTHER。  -->  
	      <setting name="jdbcTypeForNull" value="OTHER"/>  
	    <!--   指定哪个对象的方法触发一次延迟加载。  -->  
	      <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>  
	    </settings> 

dataSource 标签

Mybatis 中访问数据库,可以连接池技术,但它采用的是自己的连接池技术。在 Mybatis 的 mybatis-config.xml 配置文件中,通过<dataSource type=”pooled”>来实现 Mybatis 中连接池的配置。

dataSource 类型

在这里插入图片描述
上图看出 Mybatis 将数据源分为三类:
1、UNPOOLED:不使用连接池的数据源。
2、POOLED:使用连接池的数据源。
3、JNDI:使用 JNDI 实现的数据源。
其中 UNPOOLED、POOLED 数据源实现了 javax.sq.DataSource 接口,JNDI 和前面两个实现方式不同(了解)。
在这里插入图片描述

dataSource 配置

在 mybatis-config.xml 主配置文件,配置 dataSource:

<dataSource type="POOLED">
	<!--连接数据库的四个要素-->
	<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost:3306/ssm?useUnicode=true&amp;characterEncoding=utf-8&amp;useSSL=false&amp;serverTimezone=UTC"/>
    <property name="username" value="root"/>
    <property name="password" value="123"/>
</dataSource>

MyBatis 在初始化时,根据<dataSource>的 type 属性来创建相应类型的的数据源 DataSource,即:
1、type=”POOLED”:MyBatis 会创建 PooledDataSource 实例。
2、type=”UNPOOLED”:MyBatis 会创建 UnpooledDataSource 实例。
3、type=”JNDI”:MyBatis 会从 JNDI 服务上查找 DataSource 实例,然后返回使用。

事务

默认需要手动提交事务

1、Mybatis 框架是对 JDBC 的封装,所以 Mybatis 框架的事务控制方式,本身也是用 JDBC 的 Connection 对象的 commit(), rollback()。
2、Connection 对象的 setAutoCommit() 方法来设置事务提交方式的。自动提交和手工提交。
3、<transactionManager type="JDBC"/>该标签用于指定 MyBatis 所使用的事务管理器。MyBatis 支持两种事务管理器类型:JDBC 与 MANAGED。
4、JDBC:使用 JDBC 的事务管理机制。即通过 Connection 的 commit() 方法提交,通过 rollback() 方法回滚。但默认情况下,MyBatis 将自动提交功能关闭了,改为了手动提交。即程序中需要显式的对 事务进行提交或回滚。从日志的输出信息中可以看到。
在这里插入图片描述
MANAGED:由容器来管理事务的整个生命周期(如 Spring 容器)。

自动提交事务

1、设置自动提交的方式,factory 的 openSession() 分为有参数和无参数的。
在这里插入图片描述
有参数为 true,使用自动提交,可以修改 MyBatisUtil 的 getSqlSession()方法。

session = factory.openSession(true);

再执行 insert 操作,无需执行 session.commit() 事务是自动提交的。

使用数据库属性配置文件

为了方便对数据库连接的管理,DB 连接四要素数据一般都是存放在一个专门的属性文件中的。MyBatis 主配置文件需要从这个属性文件中读取这些数据。目的是便于修改,保存,处理多个数据库的信息。

  • 步骤
    1、在 classpath 路径下,创建 properties 文件
    在 resources 目录创建 xxxx.properties 文件,文件名称自定义(例如 jdbc.properties)。在属性配置文件中定义数据,格式是 key=value,key: 一般使用点(.)做多级目录的(例如 jdbc.mysql.driver)。
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql//.....
jdbc.username=root
jdbc.password=123456

2、在 mybatis 的主配置文件,使用<property>指定文件的位置:
在这里插入图片描述
或者在需要使用值的地方,使用${key}
在这里插入图片描述

typeAliases(类型别名)

Mybatis 支持默认别名,我们也可以采用自定义别名方式来开发,主要使用在

posted @ 2022-05-17 21:45  YU_UY  阅读(144)  评论(0编辑  收藏  举报