玩命加载中 . . .

Mybatis 简介和xml配置


Mybatis的介绍和xml配置

本文code地址:
https://gitee.com/caimengzhi/code_java/tree/master/mybatis

1. 数据库操作框架的历程

1.1 JDBC

  JDBC(Java Data Base Connection,java数据库连接)是一种用于执行SQL语句的Java API,可以为多种关系数据库提供统一访问,它由一组用Java语言编写的类和接口组成.JDBC提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够编写数据库应用程序

  • 优点:运行期:快捷、高效
  • 缺点:编辑期:代码量大、繁琐异常处理、不支持数据库跨平台

jdbc

https://blog.mybatis.org/

1.2 DBUtils

DBUtils是Java编程中的数据库操作实用工具,小巧简单实用。DBUtils封装了对JDBC的操作,简化了JDBC操作,可以少写代码。

DBUtils三个核心功能介绍

  • QueryRunner中提供对sql语句操作的API
  • ResultSetHandler接口,用于定义select操作后,怎样封装结果集
  • DBUtils类,它就是一个工具类,定义了关闭资源与事务处理的方法

1.3 Hibernate

​ Hibernate 是由 Gavin King 于 2001 年创建的开放源代码的对象关系框架。它强大且高效的构建具有关系对象持久性和查询服务的 Java 应用程序。

​ Hibernate 将 Java 类映射到数据库表中,从 Java 数据类型中映射到 SQL 数据类型中,并把开发人员从 95% 的公共数据持续性编程工作中解放出来。

​ Hibernate 是传统 Java 对象和数据库服务器之间的桥梁,用来处理基于 O/R 映射机制和模式的那些对象。

hibernate

Hibernate 优势

  • Hibernate 使用 XML 文件来处理映射 Java 类别到数据库表格中,并且不用编写任何代码。

  • 为在数据库中直接储存和检索 Java 对象提供简单的 APIs。

  • 如果在数据库中或任何其它表格中出现变化,那么仅需要改变 XML 文件属性。

  • 抽象不熟悉的 SQL 类型,并为我们提供工作中所熟悉的 Java 对象。

  • Hibernate 不需要应用程序服务器来操作。

  • 操控你数据库中对象复杂的关联。

  • 最小化与访问数据库的智能提取策略。

  • 提供简单的数据询问。

    Hibernate劣势

  • hibernate的完全封装导致无法使用数据的一些功能。

  • Hibernate的缓存问题。

  • Hibernate对于代码的耦合度太高。

  • Hibernate寻找bug困难。

  • Hibernate批量数据操作需要大量的内存空间而且执行过程中需要的对象太多

    (4) JDBCTemplate

​ JdbcTemplate针对数据查询提供了多个重载的模板方法,你可以根据需要选用不同的模板方法.如果你的查询很简单,仅仅是传入相应SQL或者相关参数,然后取得一个单一的结果,那么你可以选择如下一组便利的模板方法。

​ 优点:运行期:高效、内嵌Spring框架中、支持基于AOP的声明式事务
​ 缺点:必须于Spring框架结合在一起使用、不支持数据库跨平台、默认没有缓存

2. Mybatis

​ MyBatis 是一款优秀的持久层框架,它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。

2.1 优点

  • 与JDBC相比,减少了50%的代码量
  • 最简单的持久化框架,简单易学
  • SQL代码从程序代码中彻底分离出来,可以重用
  • 提供XML标签,支持编写动态SQL
  • 提供映射标签,支持对象与数据库的ORM字段关系映射

2.2 缺点

  • SQL语句编写工作量大,熟练度要高
  • 数据库移植性比较差,如果需要切换数据库的话,SQL语句会有很大的差异

3. Mybatis项目

3.1 创建普通的maven项目

3.2 导入相关的依赖

pom.xml的配置文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cmz</groupId>
    <artifactId>mybatis_demo1</artifactId>
    <version>1.0-SNAPSHOT</version>

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

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

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

</project>

3.3 创建对应的数据表

数据表我们使用之前的demo数据库

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 50709
 Source Host           : localhost:3306
 Source Schema         : demo

 Target Server Type    : MySQL
 Target Server Version : 50709
 File Encoding         : 65001

 Date: 09/04/2020 14:45:02
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for account
-- ----------------------------
DROP TABLE IF EXISTS `account`;
CREATE TABLE `account`  (
  `username` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '',
  `balance` double NULL DEFAULT NULL,
  PRIMARY KEY (`username`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of account
-- ----------------------------
INSERT INTO `account` VALUES ('lisi', 1000);
INSERT INTO `account` VALUES ('zhangsan', 900);

-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book`  (
  `id` int(10) NOT NULL,
  `book_name` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `price` double NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES (1, '西游记', 100);
INSERT INTO `book` VALUES (2, '水浒传', 100);
INSERT INTO `book` VALUES (3, '三国演义', 100);
INSERT INTO `book` VALUES (4, '红楼梦', 100);

-- ----------------------------
-- Table structure for book_stock
-- ----------------------------
DROP TABLE IF EXISTS `book_stock`;
CREATE TABLE `book_stock`  (
  `id` int(255) NOT NULL DEFAULT 0,
  `stock` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of book_stock
-- ----------------------------
INSERT INTO `book_stock` VALUES (1, 999);
INSERT INTO `book_stock` VALUES (2, 1000);
INSERT INTO `book_stock` VALUES (3, 1000);
INSERT INTO `book_stock` VALUES (4, 1000);

-- ----------------------------
-- Table structure for dept
-- ----------------------------
DROP TABLE IF EXISTS `dept`;
CREATE TABLE `dept`  (
  `DEPTNO` int(11) NOT NULL,
  `DNAME` varchar(14) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `LOC` varchar(13) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`DEPTNO`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of dept
-- ----------------------------
INSERT INTO `dept` VALUES (10, 'ACCOUNTING', 'NEW YORK');
INSERT INTO `dept` VALUES (20, 'RESEARCH', 'DALLAS');
INSERT INTO `dept` VALUES (30, 'SALES', 'CHICAGO');
INSERT INTO `dept` VALUES (40, 'OPERATIONS', 'BOSTON');

-- ----------------------------
-- Table structure for emp
-- ----------------------------
DROP TABLE IF EXISTS `emp`;
CREATE TABLE `emp`  (
  `EMPNO` int(11) NOT NULL,
  `ENAME` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `JOB` varchar(9) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `MGR` double NULL DEFAULT NULL,
  `HIREDATE` date NULL DEFAULT NULL,
  `SAL` double NULL DEFAULT NULL,
  `COMM` double NULL DEFAULT NULL,
  `DEPTNO` int(11) NULL DEFAULT NULL,
  PRIMARY KEY (`EMPNO`) USING BTREE,
  INDEX `DEPTNO`(`DEPTNO`) USING BTREE,
  CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`DEPTNO`) REFERENCES `dept` (`DEPTNO`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of emp
-- ----------------------------
INSERT INTO `emp` VALUES (7369, 'SMITH', 'CLERK', 7902, '1980-12-17', 800, NULL, 20);
INSERT INTO `emp` VALUES (7499, 'ALLEN', 'SALESMAN', 7698, '1981-02-20', 1600, 300, 30);
INSERT INTO `emp` VALUES (7521, 'WARD', 'SALESMAN', 7698, '1981-02-22', 1250, 500, 30);
INSERT INTO `emp` VALUES (7566, 'JONES', 'MANAGER', 7839, '1981-04-02', 2975, NULL, 20);
INSERT INTO `emp` VALUES (7654, 'MARTIN', 'SALESMAN', 7698, '1981-09-28', 1250, 1400, 30);
INSERT INTO `emp` VALUES (7698, 'BLAKE', 'MANAGER', 7839, '1981-05-01', 2850, NULL, 30);
INSERT INTO `emp` VALUES (7782, 'CLARK', 'MANAGER', 7839, '1981-06-09', 2450, NULL, 10);
INSERT INTO `emp` VALUES (7788, 'SCOTT', 'ANALYST', 7566, '1987-07-13', 3000, NULL, 20);
INSERT INTO `emp` VALUES (7839, 'KING', 'PRESIDENT', NULL, '1981-11-17', 5000, NULL, 10);
INSERT INTO `emp` VALUES (7844, 'TURNER', 'SALESMAN', 7698, '1981-09-08', 1500, 0, 30);
INSERT INTO `emp` VALUES (7876, 'ADAMS', 'CLERK', 7788, '1987-07-13', 1100, NULL, 20);
INSERT INTO `emp` VALUES (7900, 'JAMES', 'CLERK', 7698, '1981-12-03', 950, NULL, 30);
INSERT INTO `emp` VALUES (7902, 'FORD', 'ANALYST', 7566, '1981-12-03', 3000, NULL, 20);
INSERT INTO `emp` VALUES (7934, 'MILLER', 'CLERK', 7782, '1982-01-23', 1300, NULL, 10);

-- ----------------------------
-- Table structure for salgrade
-- ----------------------------
DROP TABLE IF EXISTS `salgrade`;
CREATE TABLE `salgrade`  (
  `GRADE` int(11) NULL DEFAULT NULL,
  `LOSAL` double NULL DEFAULT NULL,
  `HISAL` double NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of salgrade
-- ----------------------------
INSERT INTO `salgrade` VALUES (1, 700, 1200);
INSERT INTO `salgrade` VALUES (2, 1201, 1400);
INSERT INTO `salgrade` VALUES (3, 1401, 2000);
INSERT INTO `salgrade` VALUES (4, 2001, 3000);
INSERT INTO `salgrade` VALUES (5, 3001, 9999);

-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user`  (
  `id` int(11) NOT NULL,
  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'zhangsan');
INSERT INTO `user` VALUES (2, 'lisi ');

SET FOREIGN_KEY_CHECKS = 1;

3.4 建与表对应实体类对象

emp.java

package com.cmz.bean;

import java.util.Date;

/**
 * @author summer
 * @create 2020-04-08 16:33
 */
public class Emp {
    private Integer empno;
    private String ename;
    private String job;
    private Integer mgr;
    private Date hiredate;
    private Double sal;
    private Double common;
    private Integer deptno;

    public Emp() {
    }

    public Emp(Integer empno, String ename, String job, Integer mgr, Date hiredate, Double sal, Double common, Integer deptno) {
        this.empno = empno;
        this.ename = ename;
        this.job = job;
        this.mgr = mgr;
        this.hiredate = hiredate;
        this.sal = sal;
        this.common = common;
        this.deptno = deptno;
    }

    public Integer getEmpno() {
        return empno;
    }

    public void setEmpno(Integer empno) {
        this.empno = empno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public String getJob() {
        return job;
    }

    public void setJob(String job) {
        this.job = job;
    }

    public Integer getMgr() {
        return mgr;
    }

    public void setMgr(Integer mgr) {
        this.mgr = mgr;
    }

    public Date getHiredate() {
        return hiredate;
    }

    public void setHiredate(Date hiredate) {
        this.hiredate = hiredate;
    }

    public Double getSal() {
        return sal;
    }

    public void setSal(Double sal) {
        this.sal = sal;
    }

    public Double getCommon() {
        return common;
    }

    public void setCommon(Double common) {
        this.common = common;
    }

    public Integer getDeptno() {
        return deptno;
    }

    public void setDeptno(Integer deptno) {
        this.deptno = deptno;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "empno=" + empno +
                ", ename='" + ename + '\'' +
                ", job='" + job + '\'' +
                ", mgr=" + mgr +
                ", hiredate=" + hiredate +
                ", sal=" + sal +
                ", common=" + common +
                ", deptno=" + deptno +
                '}';
    }
}

3.5 创建对应的dao类

EmpDao.java

package com.cmz.dao;

import com.cmz.bean.Emp;

/**
 * @author summer
 * @create 2020-04-08 16:35
 */
public interface EmpDao {

    public Integer save(Emp emp);
    public Integer update(Emp emp);
    public Integer delete(Integer empno);
    public Emp selectEmpByEmpno(Integer empno);
}

3.6 编写配置文件

db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/demo?serverTimezone=UTC
username=root
password=root

注意: 一定要加serverTimezone=UTC,否则会报错

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">
<configuration>
    <properties resource="db.properties"></properties>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据库连接-->
            <dataSource type="POOLED">
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
     <!--引入每一个接口对应点xml文件-->
    <mappers>
        <mapper resource="EmpDao.xml"/>
    </mappers>
</configuration>

EmpDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--namespace:编写接口的全类名,就是告诉要实现该配置文件是哪个接口的具体实现-->
<mapper namespace="com.cmz.dao.EmpDao">
    <!--
    select:表示这个操作是一个查询操作
    id表示的是要匹配的方法的名称
    resultType:表示返回值的类型,查询操作必须要包含返回值的类型
    #{属性名}:表示要传递的参数的名称
    -->
    <select id="selectEmpByEmpno" resultType="com.cmz.bean.Emp">
        select * from emp where empno = #{empno}
    </select>

    <insert id="save">
        insert into emp(empno,ename) values(#{empno},#{ename})
    </insert>

    <insert id="update">
        update emp set sal=#{sal} where empno=#{empno}
    </insert>

    <delete id="delete">
        delete from emp where empno=#{empno}
    </delete>
</mapper>

日志配置

# 全局日志配置
log4j.rootLogger=INFO, stdout
# MyBatis 日志配置
log4j.logger.com.cmz=TRACE
# 控制台输出
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n

执行以下代码

/*查询*/
    @Test
    public void test05() throws IOException {
        //获取与数据库相关的会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取对应的映射接口对象
        UserDao mapper = sqlSession.getMapper(UserDao.class);
        //执行对应的sql
        User user = mapper.selectUserById(1);
        System.out.println(user);
        sqlSession.close();
    }

会打印类型如下信息

DEBUG [main] - ==>  Preparing: select * from user where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <==    Columns: id, user_name
TRACE [main] - <==        Row: 1, zhangsan
DEBUG [main] - <==      Total: 1
User{id=1, userName='zhangsan'}

3.7 编写测试类[增删改查]

MyTest.java

import com.cmz.bean.Emp;
import com.cmz.dao.EmpDao;
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.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

/**
 * @author summer
 * @create 2020-04-08 16:44
 */
public class MyTest {
    SqlSessionFactory sqlSessionFactory = null;

    @Before
    public void init(){
        String resource = "mybatis_config.xml";
        InputStream inputStream = null;
        try {
            inputStream = Resources.getResourceAsStream(resource);
        } catch (IOException e) {
            e.printStackTrace();
        }
        sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
    }

    /*查询*/
    @Test
    public void test01() throws IOException {
        String resource = "mybatis_config.xml";
        InputStream inputStream = Resources.getResourceAsStream(resource);
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

        //获取与数据库相关的会话
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取对应的映射接口对象
        EmpDao mapper = sqlSession.getMapper(EmpDao.class);
        //执行对应的sql
        Emp emp = mapper.selectEmpByEmpno(7369);
        System.out.println(emp);
        sqlSession.close();
    }

    /*增加*/
    @Test
    public void test02(){
        /*SqlSession sqlSession = sqlSessionFactory.openSession(true);*/ /*默认是不自动提交事务的。需要自己commit提交*/
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpDao mapper = sqlSession.getMapper(EmpDao.class);
        Emp emp = new Emp();
        emp.setEmpno(3333);
        emp.setEname("张三");
        Integer count = mapper.save(emp);/*传入的是对象*/
        System.out.println("插入成功条数: "+count);
        sqlSession.commit();
        sqlSession.close();
    }

    /*修改*/
    @Test
    public void test03(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpDao mapper = sqlSession.getMapper(EmpDao.class);
        Emp emp = new Emp();
        emp.setEmpno(3333);
        emp.setEname("张三");
        emp.setSal(500.0);
        Integer count = mapper.update(emp);/*传入的是对象*/
        System.out.println("修改成功条数: "+count);
        sqlSession.commit();
        sqlSession.close();
    }

    /*删除*/
    @Test
    public void test04(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        EmpDao mapper = sqlSession.getMapper(EmpDao.class);
        Emp emp = new Emp();
        Integer count = mapper.delete(3333);
        System.out.println("删除成功条数: "+count);
        sqlSession.commit();
        sqlSession.close();
    }
}

4 配置文件详解

​ 在mybatis的项目中,我们发现了有一个mybatis-config.xml的配置文件,这个配置文件是mybatis的全局配置文件,用来进行相关的全局配置,在任何操作下都生效的配置。下面我们要针对其中的属性做详细的解释,方便大家在后续使用的时候更加熟练。

配置文件中的配置有先后关系

<!ELEMENT configuration (
    properties?, 
    settings?,
    typeAliases?,
    typeHandlers?,
    objectFactory?, 
    objectWrapperFactory?,
    reflectorFactory?, 
    plugins?, 
    environments?, 
    databaseIdProvider?, 
    mappers?)>

    从上到下书写,否则会报错。你可以某个标签没有,但是顺序不能错。

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">
<configuration>
    <!--引入外部配置文件,类似于Spring中的property-placeholder
    resource:从类路径引入
    url:从磁盘路径或者网络路径引入
    -->
    <properties resource="db.properties"></properties>
    <!--用来控制mybatis运行时的行为,是mybatis中的重要配置-->
    <settings>
        <!--设置列名映射的时候是否是驼峰标识-->
        <setting name="mapUnderscoreToCamelCase" value="true"/>
    </settings>
    <!--typeAliases表示为我们引用的实体类起别名,默认情况下我们需要写类的完全限定名
    如果在此处做了配置,那么可以直接写类的名称,在type中配置上类的完全限定名,在使用的时候可以忽略大小写
    还可以通过alias属性来表示类的别名
    -->
    <typeAliases>
<!--        <typeAlias type="com.mashibing.bean.Emp" alias="Emp"></typeAlias>-->
        <!--如果需要引用多个类,那么给每一个类起别名肯定会很麻烦,因此可以指定对应的包名,那么默认用的是类名-->
        <package name="com.mashibing.bean"/>
    </typeAliases>
    <!--
    在实际的开发过程中,我们可能分为开发环境,生产环境,测试环境等等,每个环境的配置可以是不一样的
    environment就用来表示不同环境的细节配置,每一个环境中都需要一个事务管理器以及数据源的配置
    我们在后续的项目开发中几乎都是使用spring中配置的数据源和事务管理器来配置,此处不需要研究
    -->
    <!--default:用来选择需要的环境-->
    <environments default="development">
        <!--id:表示不同环境的名称-->
        <environment id="development">
            <transactionManager type="JDBC"/>
            <!--配置数据库连接-->
            <dataSource type="POOLED">
                <!--使用${}来引入外部变量-->
                <property name="driver" value="${driverClassname}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
    <!--
    在不同的数据库中,可能sql语句的写法是不一样的,为了增强移植性,可以提供不同数据库的操作实现
    在编写不同的sql语句的时候,可以指定databaseId属性来标识当前sql语句可以运行在哪个数据库中
    -->
    <databaseIdProvider type="DB_VENDOR">
        <property name="MySQL" value="mysql"/>
        <property name="SQL Server" value="sqlserver"/>
        <property name="Oracle" value="orcl"/>
    </databaseIdProvider>

    <!--将sql的映射文件适用mappers进行映射-->
    <mappers>
        <!--
        指定具体的不同的配置文件
        class:直接引入接口的全类名,可以将xml文件放在dao的同级目录下,并且设置相同的文件名称,同时可以使用注解的方式来进行相关的配置
        url:可以从磁盘或者网络路径查找sql映射文件
        resource:在类路径下寻找sql映射文件
        -->
<!--        <mapper resource="EmpDao.xml"/>
        <mapper resource="UserDao.xml"/>
        <mapper class="com.mashibing.dao.EmpDaoAnnotation"></mapper>-->
        <!--
        当包含多个配置文件或者配置类的时候,可以使用批量注册的功能,也就是引入对应的包,而不是具体的配置文件或者类
        但是需要注意的是,
        1、如果使用的配置文件的形式,必须要将配置文件跟dao类放在一起,这样才能找到对应的配置文件.
            如果是maven的项目的话,还需要添加以下配置,原因是maven在编译的文件的时候只会编译java文件
                <build>
                    <resources>
                        <resource>
                            <directory>src/main/java</directory>
                        <includes>
                            <include>**/*.xml</include>
                        </includes>
                    </resource>
                    </resources>
                </build>

        2、将配置文件在resources资源路径下创建跟dao相同的包名
        -->
        <package name="com.mashibing.dao"/>
    </mappers>
</configuration>

4.1 起别名

别名不区分大小写,但是推荐全类名写法

4.1.1 typeAliases单个别名

表示在引入实体类的名称时候,可以使用别名,而不需要写完全限定名

<!-- typeAlias: 为某个java类型起别名
type: 指定要起别名的类型全类名。默认别名是类名小写,emp
alias: 指定新的别名,别名不区分大小写。
-->
<typeAliases>
    <typeAlias type="com.cmz.bean.Emp" alias="Emp"></typeAlias>
</typeAliases>

没修改上述之前,EmpDao.xml中必须指定全路径。如下

<select id="selectEmpByEmpno" resultType="com.cmz.bean.Emp">  <!--没有别名之前-->

image-20200409150248735

加入以上别名之后配置如下:

<select id="selectEmpByEmpno" resultType="Emp"> /*添加别名之后,可以简写*/

image-20200409150924042

其中别名Emp是随便你起的。以下是视频操作演示。

别名

4.1.2 package批量别名

  • 包下没有相同的类

上面提到了,可以通过别名来传递,但是以上是针对每个类去做的,每一个具体的类都需要单独来写,如果有100个类呢?那此时就需要以下方式来写了,可以指定具体的包来保证实体类不需要写完全限定名。

mybatis_config.xml

<typeAliases>
    <!--可以指定具体的包来保证实体类不需要写完全限定名
    name: 指定包名(为当前包以及包下面所有的后代包的每一个类都起一个默认别名[类名小写])
    -->
    <package name="com.cmz.bean"/>
</typeAliases>

运行那个测试类查询效果一样

DEBUG [main] - ==>  Preparing: /*添加别名之后,可以简写*/ select * from emp where empno = ? 
DEBUG [main] - ==> Parameters: 7369(Integer)
TRACE [main] - <==    Columns: EMPNO, ENAME, JOB, MGR, HIREDATE, SAL, COMM, DEPTNO
TRACE [main] - <==        Row: 7369, SMITH, CLERK, 7902.0, 1980-12-17, 800.0, null, 20
DEBUG [main] - <==      Total: 1
Emp{empno=7369, ename='SMITH', job='CLERK', mgr=7902, hiredate=Wed Dec 17 08:00:00 CST 1980, sal=800.0, common=null, deptno=20}

但是个人推荐使用全路径,因为点击那个类也就是Emp的时候,就会自动跳转到Emp.class中。简写的不行。親看如下效果:別名的時候没办法点击。1

  • 包下有相同的类。

也就是包下不同路径下,有两个相同的User.class此时若是还是使用上述批量默认别名的话,mybatis就会报错,说冲突,因为你有多个User.class。此时我们为了解决这个问题,我们可以使用注解。

image-20200414142255463

此时一旦添加注解就不能使用默认的别名了,但是全类名还是可以使用的。

4.2 properties

当需要引入外部的配置文件的时候,可以使用这样的方式,类似于<context:property-placeholder location>

  • resource:表示从当前项目的类路径中进行加载,如果用的是idea指的是resource资源目录下的配置文件
  • url:可以从当前文件系统的磁盘目录查找配置,也可以从网络上的资源进行引入
<properties resource="db.properties"></properties>

image-20200414125634566

这样就可以通过加载配置文件方式,来连接mysql数据库,而不是写在代码中,可以解耦。写在代码中的时候,变更mysql的时候会需要去改代码。mybatis结合spring的时候,这个标签可以不用写,都交给spring去管理了。

4.2 settings

  • mapUnderscoreToCamelCase

开启驼峰标识验证,默认是false,即从经典数据库列名A_COLUMN到经典的Java属性名aColumn的类型映射。

数据库

mysql> desc user;
+-----------+--------------+------+-----+---------+----------------+
| Field     | Type         | Null | Key | Default | Extra          |
+-----------+--------------+------+-----+---------+----------------+
| id        | int(11)      | NO   | PRI | NULL    | auto_increment |
| user_name | varchar(255) | YES  |     | NULL    |                |
+-----------+--------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

mysql> select * from user;
+----+-----------+
| id | user_name |
+----+-----------+
|  1 | zhangsan  |
|  2 | zhangsan  |
|  3 | lisi      |
|  4 | lisi      |
|  5 | lisi      |
|  6 | lisi      |
|  7 | lisi      |
|  8 | lisi      |
|  9 | lisi      |
+----+-----------+
9 rows in set (0.00 sec)

而java类

package com.cmz.bean;

/**
 * @author summer
 * @create 2020-04-08 17:42
 */
public class User {
    private Integer id;
    private String userName;

    public User() {
    }

    public User(Integer id, String userName) {
        this.id = id;
        this.userName = userName;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userName='" + userName + '\'' +
                '}';
    }
}

从上面可以看出,mysql的字段user_name和Java的属性userName不对应,可以在没配置驼峰语法之前是这个字段是没办法显示的。

image-20200414133919192

此时也可以通过alias显示。

image-20200414134113567

但是我们可以通过开启驼峰语法,关联映射。

<settings>
    <!--开启驼峰标识验证-->
    <setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>

image-20200414134215949

4.3 typeHandlers

<typeHandlers>
    <typeHandler handler="" ></typeHandler>
    <package name=""/>
</typeHandlers>

4.4 objectFactory

<!--当需要自定义对象工厂的时候实现此标签,完成结果集到java对象实例化的过程-->
<objectFactory type=""></objectFactory>

4.5 plugins

mybatis分页器插件

https://pagehelper.github.io/

4.6 environments

https://mybatis.org/mybatis-3/zh/configuration.html#environments

MyBatis 可以配置成适应多种环境,这种机制有助于将 SQL 映射应用于多种数据库之中, 现实情况下有多种理由需要这么做。例如,开发、测试和生产环境需要有不同的配置;或者想在具有相同 Schema 的多个生产数据库中使用相同的 SQL 映射。还有许多类似的使用场景。

<environments default="development">
    <!--配置具体的环境属性
    default: 可以选择指定的某种环境。
        id:表示当前环境的名称
            transactionManager: 事务管理器
                type: 事务管理器的类型,JDBC|MANGED|自定义事务

    -->
    <!--测试环境-->
    <environment id="test">
        <transactionManager type="JDBC"></transactionManager>
        <dataSource type=""></dataSource>
    </environment>

    <!--开发环境-->
    <environment id="development">
        <!--事务管理器,每一种数据源都需要配置具体的事务管理器
       type:表示事务管理器的类型
       jdbc:使用jdbc原生的事务控制
       managed:什么都没做
       -->
        <transactionManager type="JDBC"/>

        <!--https://mybatis.org/mybatis-3/zh/configuration.html#environments-->
        <!--配置具体的数据源的类型
        type:表示数据源的类型
        pooled:使用数据库连接池
        unpooled:每次都打开和关闭一个链接
        -->
        <dataSource type="POOLED">
     <!--链接数据的时候需要添加的必备的参数,一般是四个,如果是连接池的话,可以设置连接最大个数等相关信息-->
            <property name="driver" value="${driver}"/>
            <property name="url" value="${url}"/>
            <property name="username" value="${username}"/>
            <property name="password" value="${password}"/>
        </dataSource>
    </environment>
</environments>

4.7 databaseIdProvider

https://mybatis.org/mybatis-3/zh/configuration.html#databaseIdProvider

MyBatis 可以根据不同的数据库厂商执行不同的语句,这种多厂商的支持是基于映射语句中的 databaseId 属性。 MyBatis 会加载带有匹配当前数据库 databaseId 属性和所有不带 databaseId 属性的语句。 如果同时找到带有 databaseId 和不带 databaseId 的相同语句,则后者会被舍弃。 为支持多厂商特性,只要像下面这样在 mybatis-config.xml 文件中加入 databaseIdProvider 即可:

<databaseIdProvider type="DB_VENDOR" />

databaseIdProvider 对应的 DB_VENDOR 实现会将 databaseId 设置为 DatabaseMetaData#getDatabaseProductName() 返回的字符串。 由于通常情况下这些字符串都非常长,而且相同产品的不同版本会返回不同的值,你可能想通过设置属性别名来使其变短:

mybati_config.xml

<!--提供了不同的数据库厂商的标识,当有数据库移植的需求的时候,
可以根据不同的数据库来执行不同的sql语句,用来扩展数据库的移植性
-->
<databaseIdProvider type="DB_VENDOR">
    <property name="MySQL" value="mysql"/>
    <property name="SQL Server" value="sqlserver"/>
    <property name="Oracle" value="oracle"/>
</databaseIdProvider>

提供了属性别名时,databaseIdProvider 的 DB_VENDOR 实现会将 databaseId 设置为数据库产品名与属性中的名称第一个相匹配的值,如果没有匹配的属性,将会设置为 “null”。如下例子,我同一个查询,

  • 使用以后使用mysql数据库的话,EmpDao.xml中的语句的databaseId="mysql"
  • 若是以后想使用oracle的话,EmpDao.xml中的语句的databaseId="oracle"

EmpDao.xml

<select id="selectEmpByEmpno" resultType="com.cmz.bean.Emp" databaseId="mysql"> 
    select * from emp where empno = #{empno}
</select>

<select id="selectEmpByEmpno" resultType="com.cmz.bean.Emp" databaseId="oracle">
    select * from emp where empno = #{empno}
</select>

其中databaseId后面的取值一定是上面databaseIdProvider里面的配置的值,databaseId配置只能等于mybati_config.xml中之前配置好的databaseIdProvider的那几个值,否则报错。

3

不过蛋疼的事情是,一般不这么干。java始终还是比django差太TMD的大了。Django根本都不需要这样干,直接改配置文件就可以了,sql基本不写,都是ORM框架给你搞的,那个才是真正的ORM,你妹的假的ORM框架MyBatis。

4.8 mappers

是来将mapper映射文件引入到配置文件中,方便程序启动的时候进行加载
每次在进行填写的时候需要注意,写完xml映射之后一定要添加到mybatis-config文件中

注册配置文件
resource:从项目的类路径下加载对应的映射文件d  
url:     从本地磁盘目录或者网络中引入映射文件
         file:///var/mapper/authorMapper.xml
注册接口
class:   可以直接引入类的完全限定名,可以使用注解的方式进行使用,
    1. 有sql映射,映射文件名必须和接口名同名,并且放在与接口同一个目录下
    2. 没有sql映射,所有sql都是利用注解写在接口上。
    3. 批量注解
    推荐:
        1. 比较重要复杂的Dao接口我们来写sql映射文件。
        2. 不重要简单的Dao接口为了开发快速可以使用注解。 

4.8.1 基于注解

使用注解测试,新建UserDaoAnnotation.class

package com.cmz.dao;

import com.cmz.bean.User;
import org.apache.ibatis.annotations.Select;

public interface UserDaoAnnotation {

    @Select("select * from user where id = #{id}")
    public User selectUserById(Integer id);
}

mybatis_config.xml中配置

<mappers>
    <!--<mapper resource="EmpDao.xml"/>-->
    <!--<mapper resource="UserDao.xml"/>-->
    <mapper class="com.cmz.dao.UserDaoAnnotation"></mapper>
</mappers>

测试类代码

/*查询*/
@Test
public void test06() throws IOException {
    //获取与数据库相关的会话
    SqlSession sqlSession = sqlSessionFactory.openSession();
    //获取对应的映射接口对象
    UserDaoAnnotation userDaoAnnotation = sqlSession.getMapper(UserDaoAnnotation.class);
    //执行对应的sql
    User user = userDaoAnnotation.selectUserById(1);
    System.out.println(user);
    sqlSession.close();
}

运行结果

DEBUG [main] - ==>  Preparing: select * from user where id = ? 
DEBUG [main] - ==> Parameters: 1(Integer)
TRACE [main] - <==    Columns: id, user_name
TRACE [main] - <==        Row: 1, zhangsan
DEBUG [main] - <==      Total: 1
User{id=1, userName='zhangsan'}

java就tmd一样,贼乱。什么都是乱糟糟的。无奈java还是你大爷,生态太大了。

4

以上是我单独测试userDaoAnnotation注解方式。所以屏蔽了上面两个。

4.8.2 不基于注解

如果不想以注解的方式引入呢?如果想要class的方式引入配置文件,可以将xml文件添加到具体的类的同级目录下

方法1: 如果是maven的项目的话,需要添加如下配置,因为maven默认只会编译java文件,需要把xml文件也添加到指定目录中,把以下加入maven中

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

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.cmz</groupId>
    <artifactId>mybatis_demo1</artifactId>
    <version>1.0-SNAPSHOT</version>

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

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

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

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

    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

5


方法2: 在resource资源目录下,创建跟dao层一样的同级目录即可,将配置文件放到指定的目录

6

  • 如果需要引入多个配置文件,可以直接定义包的名称

    resource目录下配置的映射文件必须要具体相同的目录

mybatis_config.xml

<mappers>
    <!--<mapper resource="EmpDao.xml"/>-->
    <!--<mapper resource="UserDao.xml"/>-->
    <!--<mapper class="com.cmz.dao.UserDaoAnnotation"></mapper>-->
    <!--<mapper class="com.cmz.dao.UserDao"></mapper>-->

    <!--如果需要引入多个配置文件,可以直接定义包的名称
    resource目录下配置的映射文件必须要具体相同的目录
    -->
    <package name="com.cmz.dao"/>
</mappers>

文章作者: 夏天
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 夏天 !
--------本文结束感谢您的阅读!---------

如果文章能够帮到您的话,不妨就支持一下小编呗!

  目录