MyBatis (1)

MyBatis的使用第二部分,传送地址:MyBatis的使用(2) 使用注解的MyBatis 联合查询 分步查询 动态sql


文章目录

  • MyBatis (1)
  • 一、MyBatis简介
  • 二、第一个MyBatis程序
  • 三、使用MyBatis完成CRUD
  • 四、MyBatis配置解析
  • 1. 环境变量 (environments)
  • 2. 事务管理器 (transactionManager)
  • 3. 数据源 (dataSource)
  • 4. 属性 (properties)
  • 5. 类型别名 (typeAliases)
  • 6. 映射器 (mappers)
  • 五、MyBatis的生命周期和作用域
  • 六、ResultMap的使用
  • 七、日志工厂
  • 八、其他注意点


一、MyBatis简介

MyBatis是一款持久层框架,几乎避免了所有JDBC代码的复杂编码过程

中文文档地址:https://mybatis.org/mybatis-3/zh/index.html

二、第一个MyBatis程序

  1. 创建数据库(mybatis)和表(user)
CREATE DATABASE `mybatis`;

USE `mybatis`;

CREATE TABLE `user`(
                       `id` INT(20) NOT NULL PRIMARY KEY,
                       `name` VARCHAR(30) DEFAULT NULL,
                       `pwd` VARCHAR(30) DEFAULT NULL
)ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT INTO `user`(`id`,`name`,`pwd`) VALUES
(1,'周杰伦','123456'),
(2,'张学友','123456'),
(3,'郭富城','123890')
  1. IDEA中创建一个普通的Maven项目(POM工程)MyBatis,此工程的pom.xml中导入依赖
<dependencies>

    <!-- 导入mysql驱动 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>

    <!-- 导入MyBatis框架 -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>

    <!--导入Junit-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
</dependencies>

<!-- 将src/main/java目录下的资源也打包 -->
<build>
    <resources>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>true</filtering>
        </resource>
    </resources>
</build>
  1. 创建一个上述Maven工程的子Maven工程mybatis-01 (右键new module)
    此工程会自动导入父工程依赖的jar包,此工程的pom.xml中也加入将src/main/java打包的代码
    子工程的src/main/resources/目录下右键new → File;
    创建MyBatis的核心配置文件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核心配置文件-->
<configuration>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!-- xml文件中 "&" 需要转义成为 "&" -->
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=false&useUnicode=true&characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>

</configuration>
  1. 子工程的src/main/java/目录下创建一个包com.qizegao.utils
    编写MyBatis工具类MybatisUtils.java
public class MybatisUtils {

    //1. 获取SqlSessionFactory接口的对象

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //声明MyBatis的核心配置文件mybatis-config.xml的位置
            String resource = "mybatis-config.xml";
            InputStream resourceAsStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //2. 获取SqlSession接口的对象
    //SqlSession中包含了操作数据库的方法
    public static SqlSession getSqlSession() {
        return sqlSessionFactory.openSession();
    }
}
  1. 子工程的src/main/java目录下创建一个包com.qizegao.pojo
    编写User类
public class User {
    private int id;
    private String name;
    private String pwd;
    //以及标准java bean的其余结构
}
  1. 子工程的src/main/java目录下创建一个包com.qizegao.dao
    编写UserMapper接口(与UserDao作用一致)
public interface UserMapper {
    List<User> getUserList();
}
  1. 子工程的src/main/resources目录下创建com.qizegao.dao包
    包下创建配置文件UserMapper.xml (名字与UserMapper对应),此文件相当于之前的UserDaoImpl
<?xml version="1.0" encoding="UTF8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace属性绑定一个对应的Dao/Mapper接口,写全类名 -->
<mapper namespace="com.qizegao.dao.UserMapper">

    <!-- select标签代表查询语句 -->
    <!-- id属性对应Mapper接口中要执行的方法名 -->
    <!-- resultType属性表示查询结果的类型,写全类名 -->
    <select id="getUserList" resultType="com.qizegao.pojo.User">
       select * from user
    </select>

</mapper>
  1. 每一个Mapper.xml都需要在MyBatis的核心配置文件mybatis-config.xml中注册
    故在mybatis-config.xml中添加如下:
<mappers>
    <mapper resource="com/qizegao/dao/UserMapper.xml"/>
</mappers>
  1. 子工程的src/test/java目录下创建包com.qizegao.dao (测试包尽量与原包同名)
    包下创建测试类UserMapperTest
public class UserMapperTest {
    @Test
    public void test() {
        //1. 获取SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();

        //2. 获取UserMapper对象,执行其中的方法
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        List<User> list = userMapper.getUserList();

        //3. 打印查询结果
        System.out.println(list);

        //4. 关闭sqlSession
        sqlSession.close();
    }
}
运行结果:成功获取到数据

注意:

  1. 如果出现异常:

resultmap 里面类型 javaType_mysql

解决方式:使用IDEA自带的maven配置环境

  1. 如果出现异常:

resultmap 里面类型 javaType_数据库_02

解决方式:将Mapper.xml文件首部的UTF-8修改为UTF8

  1. 如果Mapper.xml没有在MyBatis的配置文件mybatis-config.xml中注册,则报异常:

resultmap 里面类型 javaType_mysql_03

三、使用MyBatis完成CRUD

  1. 查询
//UserMapper类中添加方法
User getUserById(int id);


<!-- UserMapper.xml的mapper标签中添加标签 -->
<!-- parameterType属性表示id属性对应的方法参数的类型 -->
<select id="getUserById" parameterType="int" resultType="com.qizegao.pojo.User">
    select * from user where id = #{id}
</select>



//测试类中添加
@Test
public void test2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    User user = userMapper.getUserById(1);
    System.out.println(user);
    //User{id=1, name='周杰伦', pwd='123456'}
    sqlSession.close();
}
  1. 插入
//UserMapper类中添加方法
int addUser(User user);




<!-- UserMapper.xml的mapper标签中添加标签 -->
<insert id="addUser" parameterType="com.qizegao.pojo.User">
    <!-- 对象中的属性可以通过#{}直接提取出来 -->
    insert into mybatis.user (id, name, pwd) values (#{id},#{name},#{pwd});
</insert>




@Test
public void test2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
    int res = userMapper.addUser(new User(7, "黎明", "33445566"));
    System.out.println("受影响的行数:" + res);//受影响的行数:1
    sqlSession.commit(); //增删改需要提交事务
    sqlSession.close();
}
  1. 修改
//UserMapper类中添加方法
int updateUser(User user);



<!-- UserMapper.xml的mapper标签中添加标签 -->
<update id="updateUser" parameterType="com.qizegao.pojo.User">
    update user set name=#{name}, pwd=#{pwd} where id=#{id}
</update>





@Test
public void test2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int i = mapper.updateUser(new User(7, "蔡虚坤", "78956"));
    System.out.println("受影响的行数:" + i); //受影响的行数:1
    sqlSession.commit(); //增删改需要提交事务
    sqlSession.close();
}
  1. 删除
//UserMapper类中添加方法
int deleteUser(int id);




<!-- UserMapper.xml的mapper标签中添加标签 -->
<delete id="deleteUser" parameterType="int">
    delete from user where id=#{id}
</delete>




public void test2() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int i = mapper.deleteUser(7);
    System.out.println("受影响的行数:" + i); //受影响的行数:1
    sqlSession.commit(); //增删改需要提交事务
    sqlSession.close();
}

四、MyBatis配置解析

在MyBatis的核心配置文件mybatis-config.xml (任意起名)的configuration标签中写配置

1. 环境变量 (environments)

MyBatis配置文件中可以配置多种环境,使用environment标签声明,但只可以选择其中一种环境,通过environments标签的default属性决定使用哪一种环境

2. 事务管理器 (transactionManager)

默认使用JDBC,其余可去中文文档查看

3. 数据源 (dataSource)

默认使用POOLED,其余可去中文文档查看

如下代码所示:

<configuration>

    <!-- 以下配置了两个环境,default标签中写某一环境的id属性值从而去使用它 -->
    <environments default="development">

        <environment id="development"> <!-- id属性给此环境起一个名称 -->
            <transactionManager type="JDBC"/> <!-- 默认 -->
            <dataSource type="POOLED"> <!-- 默认 -->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>

        <!-- 第二个环境 -->
        <environment id="newEnvironment">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="root"/>
            </dataSource>
        </environment>
    </environments>
    
</configuration>

4. 属性 (properties)

可以使用properties标签引用外部配置文件

(1) src/main/resources目录下创建一个配置文件db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatisuseSSL=false&useUnicode=true&characterEncoding=UTF-8

(2) mybatis-config.xml中编写

<configuration>

    <!-- 引入外部配置文件 -->
    <properties resource="db.properties">
        <!-- properties标签中也可以声明key - value,与外部配置文件配合使用 -->
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </properties>

    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <!-- 使用${}动态获取配置文件声明的key - value -->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>

</configuration>

注意:

  1. 如果外部配置文件的key和properties标签中声明的key同名,优先使用配置文件的
  2. mybatis - config.xml文件中congratulation标签中的标签声明有顺序要求

resultmap 里面类型 javaType_数据库_04

5. 类型别名 (typeAliases)

类型别名存在的意义是减少全类名的冗余,用法有两种 (在配置文件mybatis - config.xml中)

(1) 给全类名起别名

<typeAliases>
    <!-- 以后在Mapper.xml中使用此类型时无需再写全类名,直接写User即可 -->
    <typeAlias type="com.qizegao.pojo.User" alias="User"/>
</typeAliases>

(2) 扫描指定包下的类,某一类的别名默认是类名首字母小写

<typeAliases>
    <!-- 此包下的User类的别名成为user -->
    <package name="com.qizegao.pojo"/>
</typeAliases>

注意:可以在对应的类上加注解@Alias(“xxx”),则类名的别名成为指定的xxx

6. 映射器 (mappers)

用来注册绑定的Mapper.xml文件,有三种方式
每个Mapper.xml文件都需要在MyBatis的核心配置文件中注册

(1) 使用resources属性

<mappers>
    <mapper resource="com/qizegao/dao/UserMapper.xml"></mapper>
</mappers>

(2) 使用class属性

<mappers>
    <!-- class属性中写Mapper.xml文件绑定的Mapper接口 -->
    <mapper class="com.qizegao.dao.UserMapper"></mapper>
    <!--
        1. 接口和其Mapper.xml配置文件必须同名
        2. 接口和其Mapper.xml配置文件必须在同一个包下
    -->
</mappers>

(3) 使用package标签

<mappers>
    <!-- package标签可以扫描指定包下的Mapper.xml文件 -->
    <package name="com.qizegao.dao"/>
    <!--
        1. 接口和其Mapper.xml配置文件必须同名
        2. 接口和其Mapper.xml配置文件必须在同一个包下
    -->
</mappers>

五、MyBatis的生命周期和作用域

如图所示:

resultmap 里面类型 javaType_mysql_05

  1. SqlSessionFactoryBuilder

使用其创建了SqlSessionFactory之后,就不再需要它了

  1. SqlSessionFactory

(1) 可以理解为数据库连接池
(2) 它一旦被创建就应该在运行期间一直存在,没有理由丢弃它或重新创建另一个实例

  1. SqlSession

(1) 可以理解为是连接到连接池的一个请求
(2) 它的实例不是线程安全的,因此不能被共享
(3) 使用完之后应该关闭,防止资源被占用

resultmap 里面类型 javaType_java_06

六、ResultMap的使用

为了解决属性名和数据库表中的列名不一致的问题,用法如下:

假设数据库表中有三列: id name pwd
假设对应类声明了三个属性: id name password

<!-- 在Mapper.xml中的mapper标签中使用 -->
<!--
    1. id属性给resultMap标签做标识
    2. type属性表示结果集要映射成为什么类型(为哪个类自定义封装规则)
-->
<resultMap id="UserMap" type="User">
    <!-- 只需要写名字不同的项目即可,无需所有属性全部声明,未声明的需要列名属性名一一对应 -->
    <!--
        1. column属性表示数据库表中的列名
        2. property属性表示类中的属性名
    -->
    <result column="pwd" property="password"/>
</resultMap>

<!-- resultMap属性指定使用哪一个resultMap标签 -->
<select id="getUserById" resultMap="UserMap"> <!-- sql语句 --> </select>

七、日志工厂

一个数据库操作出现了异常,使用日志是最好的排错助手

在mybatis-config.xml中的configuration标签中使用settings标签指明使用哪一种日志实现

常见的日志实现有两种:

(1) STDOUT_LOGGING (标准日志输出)

i. 配置文件中声明

<settings>
    <setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>

ii. 测试类中执行一条sql语句,控制台输出:

resultmap 里面类型 javaType_mybatis_07

(2) LOG4J的使用自行网上搜索

八、其他注意点

  1. ${} 和 #{} 的区别

MyBatis有两种取值方式:

#{属性名}:是预编译的方式,参数的位置都使用?替代,参数值都是预编译设置进去的;
比较安全,不会有sql注入问题

${属性名}:直接和sql语句拼串,不安全

一般都使用#{},在不支持预编译的位置要进行取值才使用${}

  1. 查询结果是Map类型

(1) 查询结果是一项封装成为一个Map对象时,resultType属性值为 ”map”

(2) 查询结果是多项封装成为一个Map对象时,需要在Mapper接口的方法上使用注解
@MapKey(“xxx”),将查询结果的xxx列作为key封装这个map,resultType属性值为
value对应的类型(不再是map)

  1. resultMap标签补充

(1) result标签用法如上所述

(2) id标签用来指定主键列的对应规则,与result标签的用法一致

主键列也可以使用result标签,但推荐使用id标签