如果你读完这篇文章,恭喜你!你的Mybatis入门了!

SSM三部曲

文章目录

第一篇 Mybatis入门

  • Mybatis的概述

    Mybatis是一个用Java语言编写的持久层框架它封装了Jdbc操作的很多细节,使开发者只需要关注sql语句本身,而无需关注注册驱动,创建连接等繁杂过程,他使用了ORMObject Relational Mapping 对象关系映射 即把数据库与实体类及实体类的属性对应起来)思想实现了结果集的封装
  • Mybatis的环境搭建

这里注意:主配置文件的标签顺序,排错会出错
在这里插入图片描述

<!--   1. 创建maven工程并导入坐标-->

    <groupId>com.mybatis</groupId>
    <artifactId>mybatis_day01_01mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.30</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>
package com.mybatis.domain;

import java.util.Date;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/8 17:42
 *
 * 2.创建实体类和dao的接口
 */
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    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;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

package com.mybatis.dao;

import com.mybatis.domain.User;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/8 17:45
 */
public interface IUserDao {
    User findAll();
}

<?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">
<!--3.   创建mybatis的主配置文件:SqlMapConfig.xml-->
<configuration>
<!--    配置环境-->
    <environments default="mysql">
<!--        配置mysql的环境-->
        <environment id="mysql">
<!--            配置事务类型-->
            <transactionManager type="JDBC"></transactionManager>
<!--            配置数据源(连接池)-->
            <dataSource type="POOLED">
<!--                配置连接数据库的4个基本信息-->
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/spring"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

<!--    指定映射配置文件  映射配置文件的是每个dao独立的配置文件-->
    <mappers>
        <mapper resource="com/mybatis/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>
<?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.mybatis.dao.IUserDao">
<!--    4.创建映射配置文件:IuserDao.xml-->
<!--    配置查询所有-->
    <select id="findAll">
        select * from user;
    </select>
</mapper>
环境搭建注意事项:
		1.创建IUserDao.xml和IUserDao.java时名称是为了和我们之前的知识保持一致
			在Mybatis中他把持久层的操作接口名称和映射文件也叫做:Mapper
			所以:IUserDao和IUserMapper是一样的
		2.在idea中创建目录时,它和包是不一样的
		3.Mybatis的映射配置文件位置必须和dao接口的包相同
		4.映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
		5.配置映射文件的操作配置(select),id属性的取值必须是dao接口的方法名

		当我们遵从了 3  4  5点之后,我在开发中就无需再写dao的实现类
  • Mybatis的入门案例

    • 1.基于XML
      • 注意:这里需要制定IUserDao.xml文件的findAll配置语句的resultType,告知Mybatis查询到的结果应该封装到哪个实体类中,否则会报异常
   <select id="findAll" resultType="com.mybatis.domain.User">
        select * from user;
    </select>
package com.mybatis.test;

import com.mybatis.dao.IUserDao;
import com.mybatis.domain.User;
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.InputStream;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/9 11:08
 * 
 * 		Xml版本
 */
public class MybatisTest{
    public static void main(String[] args) throws Exception{
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SQLSession工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SQLSession对象
        SqlSession session = factory.openSession();
        //4.使用SQLSession创建Dao接口的代理对象
        IUserDao dao = session.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> users = dao.findAll();
        for (User user:
             users) {
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        in.close();
    }


}

  • 2.基于注解
    直接将Iuser.xml文件移除,在dao接口上加上@Select注解,并指定sql语句。同时需要在SqlMapConfig.xml中的mapper配置时,使用class属性制定dao接口的全限定类名,测试类不变
public interface IUserDao {
    @Select("select * from user")
    List<User> findAll();
}

  <mappers>
<!--        <mapper resource="com/mybatis/dao/IUserDao.xml"></mapper>-->
        <mapper class="com.mybatis.dao.IUserDao"></mapper>
    </mappers>

设计模式分析

在这里插入图片描述

  • 自定义Mybatis框架

    • 自定义Mybatis的分析:Mybatis在使用代理dao的方式实现CURD只做两件事
      • 第一:创建代理对象
      • 第二:在代理对象中调用selectList
        在这里插入图片描述
    • 自定义Mybatis的编码:(利用入门案例)
      • 在入门案例中我们能看到的类:
        在这里插入图片描述

第二篇 Mybatis的基本使用

  • Mybatis的单表CRUD操作(基于代理Dao方式)

<?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.mybatis</groupId>
    <artifactId>mybatis_day02_01mybatis_CRUD</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
    </dependencies>

</project>
package com.mybatis.domain;

import java.io.Serializable;
import java.util.Date;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/10 17:54
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    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;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

//SqlMapConfig.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>
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/spring"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>

    <mappers>
        <mapper resource="com/mybatis/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>
package com.mybatis.dao;

import com.mybatis.domain.User;

import java.io.InputStream;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/11 9:51
 */
public interface IUserDao {
    /**
     * 查询所有方法
     * @return
     */
    List<User> findAll();
    /**
     * 查询一个
     */
    User findUserById(Integer userId);

    /**
     * 保存方法
     */
    void saveUser(User user);
    /**
     * 删除方法
     */
    void deleteUser(Integer userid);
    /**
     * 修改方法
     */
    void updateUser(User user);
    /**
     * 模糊查询:根据性别查询
     */
    List<User> findUserByName(String name);
    /**
     * 使用聚合函数查询
     */
    int findCount();
}

//IUserDao.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">
<mapper namespace="com.mybatis.dao.IUserDao">
<!--    查询所有用户-->
    <select id="findAll" resultType="com.mybatis.domain.User">
        select * from user;
    </select>

<!--    查询一个用户  parameterType:表示获取参数的方式-->
    <select id="findUserById" resultType="com.mybatis.domain.User" parameterType="java.lang.Integer">
        select * from user where id = #{userId};
    </select>

<!--    保存用户  -->
    <insert id="saveUser" parameterType="com.mybatis.domain.User">
        <!--细节:配置插入操作后,获取插入的id值-->
        <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
            select last_insert_id();
        </selectKey>
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});
    </insert>

<!--    删除用户 -->
    <delete id="deleteUser" parameterType="java.lang.Integer">
        delete from user where id = #{userid};
    </delete>

<!--    更新用户-->
    <update id="updateUser" parameterType="com.mybatis.domain.User">
        update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} where id = #{id};
    </update>

<!--    模糊查询-->
    <select id="findUserByName" parameterType="java.lang.String" resultType="com.mybatis.domain.User">
        select * from user where username like #{name};
    </select>

<!--    聚合函数查询-->
    <select id="findCount" resultType="int">
        select count(*) from user;
    </select>
</mapper>
package com.mybatis;

import com.mybatis.dao.IUserDao;
import com.mybatis.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/11 9:56
 */
public class MybatisTest {

    private InputStream in;
    private SqlSession sqlSession;
    private IUserDao mapper;

    @Before // 测试方法执行之前执行
    public void init() throws Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        sqlSession = factory.openSession();
        mapper = sqlSession.getMapper(IUserDao.class);
    }
    @After //测试方法执行之后执行
    public void destroy() throws Exception{
        sqlSession.close();
        in.close();
    }

    /**
     * 查询所有
     */
    @Test
    public void TestFindAll(){
            List<User> users = mapper.findAll();
            for (User user:
                 users) {
                System.out.println(user);
            }
    }

    /**
     * 查询一个
     */
    @Test
    public void TestFindUserById(){
        User user = mapper.findUserById(1);
        System.out.println(user);
    }

    /**
     * 保存
     */
    @Test
    public void saveUser(){
        User user = new User();
        user.setUsername("隔壁老李");
        user.setSex("男");
        user.setAddress("山东临沂");
        user.setBirthday(new Date());

        mapper.saveUser(user);
        /**
         *  注意这里必须提交事务,否则会回滚
         *  可以放到 destroy中,这里为了提醒
         */

        sqlSession.commit();

    }

    /**
     * 更改用户
     */
    @Test
    public void updateUser(){
        User user = new User();
        user.setId(14);
        user.setUsername("隔壁老孙");
        user.setSex("男");
        user.setAddress("山东烟台");
        user.setBirthday(new Date());

        mapper.updateUser(user);
        sqlSession.commit();
    }

    /**
     * 删除用户
     */
    @Test
    public void deleteUser(){
       mapper.deleteUser(14);
        sqlSession.commit();
    }

    /**
     * 模糊查询
     */
    @Test
    public void TestFindUserByName(){
        List<User> users = mapper.findUserByName("%王%");
        for (User user:
                users) {
            System.out.println(user);
        }
    }

    /**
     * 聚合函数查询
     */
    @Test
    public void TestFindCount(){
        int count = mapper.findCount();
        System.out.println(count);
    }
}

小细节:
		 <!--细节:配置插入操作后,获取插入的id值
				keyProperty:对应实体类中id的属性名称
				keyColumn:对应数据库表中id列的名称
				resultType:结果类型
				order:设定插入之前查询还是之后查询
			-->
    <selectKey keyProperty="id" keyColumn="id" resultType="int" order="AFTER">
        select last_insert_id();
    </selectKey>
  • Mybatis的参数和返回值(参数深入及结果集深入)

    • Mybatis的参数深入

      • OGNL表达式(Object Graphic Navigation Language 对象图导航语言) :
        他是通过对象的取值方式来获取数据,在写法上把get省略掉了
        比如:获取用户的名称
        类中的写法:user.getUsername();
        OGNL表达式写法:user.username
        • 为什么在Mybatis中可以直接写username呢?
          那是因为在parameterType中已经提供了属性所属的类,此时不需要写类名
        • OGNL表达式的使用
          在这里插入图片描述
          在这里插入图片描述
          在这里插入图片描述
          在这里插入图片描述
          在这里插入图片描述
    • Mybatis的输出结果集封装

      • 解决实体类属性和数据库列名不对应的两种方式
        • 问题:当实体类属性和数据库列名不对应时,就会出现下列情况:
          在这里插入图片描述
          在这里插入图片描述
          注意: 之所以userName可以传值是因为MySQL不区分大小写
        • 解决方案一:起别名(相比resultMap少一步封装步骤,执行效率高)
          在这里插入图片描述 在这里插入图片描述
        • 解决方案二:用配置:(使用resultMap封装结果,但是所有CRUD操作都可以引用,开发效率高)
          在这里插入图片描述 在这里插入图片描述
  • Mybatis的Dao编写(了解,这里只展示查询所有方法)

package com.mybatis.dao.impl;

import com.mybatis.dao.IUserDao;
import com.mybatis.domain.User;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/13 17:20
 */
public class UserDaoImpl implements IUserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory) {
        this.factory = factory;
    }

    public List<User> findAll() {
        //1.根据factory或去session对象
        SqlSession session = factory.openSession();
        //2.调用SqlSession中的方法,实现查询列表
        List<User> users = session.selectList("com.mybatis.dao.IUserDao.findAll");
        //3.释放资源
        session.close();
        return users;
    }
}

package com.mybatis;

import com.mybatis.dao.IUserDao;
import com.mybatis.dao.impl.UserDaoImpl;
import com.mybatis.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/11 9:56
 */
public class MybatisTest {

    private InputStream in;
    private IUserDao mapper;

    @Before // 测试方法执行之前执行
    public void init() throws Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        mapper = new UserDaoImpl(factory);
    }
    @After //测试方法执行之后执行
    public void destroy() throws Exception{
        in.close();
    }

    /**
     * 查询所有
     */
    @Test
    public void TestFindAll(){
            List<User> users = mapper.findAll();
            for (User user:
                 users) {
                System.out.println(user);
            }
    }
}

在这里插入图片描述

  • Mybatis配置的细节

    • 几个标签的使用(主配置文件 SqlMapConfig.xml)
      • properties标签

        • 用法一:直接引用
          在这里插入图片描述
        • 用法二:使用resource属性
          • resource属性:常用的
            用于指定配置文件的位置,是按照路径的写法来写,并且必须存在于类路径下
            在这里插入图片描述
            在这里插入图片描述
        • 用法三:使用url属性(可以直接将文件拖入浏览器)
          • url属性:
            是要求按照URL的写法来写地址
            URL:Uniform Resource Locator 统一资源定位符。他是可以唯一标识一个资源的位置
            写法:
            在这里插入图片描述
            在这里插入图片描述在这里插入图片描述
      • typeAlias标签& package标签

<!--    使用typeAliases配置别名,他只能配置domain中类的别名-->
    <typeAliases>
<!--        typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,党制定别名后就不再区分大小写-->
<!--        <typeAlias type="com.mybatis.domain.User" alias="user"></typeAlias>-->
<!--        package 用于指定要配置的包,当指定后,该包下的实体类都会注册别名,且类名就是别名,不再区分大小写-->
        <package name="com.mybatis.domain"/>
    </typeAliases>
<mappers>
<!--        <mapper resource="com/mybatis/dao/IUserDao.xml"></mapper>-->
<!--        package标签是用于指定dao接口所在的包,制定之后就不需要在写mapper标签了-->
        <package name="com.mybatis.dao"/>
    </mappers>

在这里插入图片描述

第三篇 Mybatis的深入和多表

  • Mybatis的连接池以及事务控制

    • Mybatis连接池使用及分析
      • 连接池的含义:连接池就是用于存储连接的一个容器
        • 容器其实就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一连接
        • 该集合还必须实现队列的特性:先进先出
      • Mybatis中的连接池:
        • 配置位置:主配置文件SqlMapConfig.xml中的DataSource标签,type属性就是表示采用何种连接池的方式

        • type属性:

          • POOLED:采用传统的javax.sql.DataSource规范中的连接池,Mybatis中有针对规范的实现
          • UNPOOLED :采用传统的获取连接方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想
          • JNDI :采用服务器提供的JNDI技术实现,来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的
            • 注意:如果不是web或者maven的war工程,是不能使用的,在这里我使用的是tomcat服务器,采用连接池就是jdbc连接池

          在这里插入图片描述

    • Mybatis事务控制的分析
      • 什么是事务
        是数据库操作的最小工作单元,是作为单个逻辑工作单元执行的一系列操作;这些操作作为一个整体一起向系统提交,要么都执行、要么都不执行;事务是一组不可再分割的操作集合(工作逻辑单元);

      • 事务的四大特性ACID

        • 1 、原子性
          事务是数据库的逻辑工作单位,事务中包含的各操作要么都做,要么都不做
        • 2 、一致性
          事 务执行的结果必须是使数据库从一个一致性状态变到另一个一致性状态。因此当数据库只包含成功事务提交的结果时,就说数据库处于一致性状态。如果数据库系统 运行中发生故障,有些事务尚未完成就被迫中断,这些未完成事务对数据库所做的修改有一部分已写入物理数据库,这时数据库就处于一种不正确的状态,或者说是 不一致的状态。
        • 3 、隔离性
          一个事务的执行不能其它事务干扰。即一个事务内部的操作及使用的数据对其它并发事务是隔离的,并发执行的各个事务之间不能互相干扰。
        • 4 、持续性
          也称永久性,指一个事务一旦提交,它对数据库中的数据的改变就应该是永久性的。接下来的其它操作或故障不应该对其执行结果有任何影响。
      • 不考虑隔离性会产生的3个问题

        • 1、脏读:脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据。

        • 2、不可重复读:一个事务两次读取同一行的数据,结果得到不同状态的结果,中间正好另一个事务更新了该数据,两次结果相异,不可被信任。通俗来讲就是:事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。

        • 3、幻读(虚读):一个事务执行两次查询,第二次结果集包含第一次中没有或某些行已经被删除的数据,造成两次结果不一致,只是另一个事务在这两次查询中间插入或删除了数据造成的。通俗来讲就是:例如事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读

      • 解决办法:四种隔离级别

        • 1、Read Uncommited(读取未提交内容)
          读未提交,顾名思义,就是一个事务可以读取另一个未提交事务的数据。但是,读未提交产生了脏读,采用读提交可以解决脏读问题
        • 2、Read Commited(读取提交内容)
          读提交,顾名思义,就是一个事务要等另一个事务提交后才能读取数据。读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。但是,读提交两次查询会产生不同的查询结果,就会造成不可重复读问题,采用重复读可以解决此问题。
        • 3、Repeatable Read(重复读)
          重复读,就是在开始读取数据(事务开启)时,不再允许修改操作。重复读可以解决不可重复读问题。应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。采用Serializable可以解决幻读问题
        • 4、Serializable(可串行化)
          Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。
  • Mybatis基于xml配置的动态SQL语句的使用

    • mappers配置文件中的几个标签:
      • if 标签
        在这里插入图片描述
      • where 标签
        在这里插入图片描述
      • foreach标签
        在这里插入图片描述
        在这里插入图片描述
      • sql标签(了解,提取重复sql语句)
        在这里插入图片描述
  • Mybatis的多表查询(必须掌握

  • 一对多
package com.mybatis.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/10 17:54
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;

    //一对多关系映射:主表实体应该包含从表实体的对象引用
    private List<Account> account;

    public List<Account> getAccount() {
        return account;
    }

    public void setAccount(List<Account> account) {
        this.account = account;
    }

    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;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}

<?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.mybatis.dao.IUserDao">

<!--    定义User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
<!--        配置user对象中accounts集合的映射-->
        <collection property="account" ofType="account">
            <id column="aid" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="userAccountMap">
        select u.*,a.id as aid,a.uid,a.money from user u left outer join account a on u.id=a.uid;
    </select>
    /**
     * 用户查询所有
     */
    @Test
    public void TestFindAll_User(){
            List<User> users = mapper.findAll();
            for (User user:
                 users) {
                System.out.println(user);
                System.out.println(user.getAccount());
            }
    }
  • 一对一
package com.mybatis.domain;

import java.io.Serializable;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/15 14:59
 */
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //一对一关系映射:从表实体应该包含主表实体的对象引用
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}

package com.mybatis.domain;

import java.io.Serializable;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/15 14:59
 */
public class Account implements Serializable {
    private Integer id;
    private Integer uid;
    private Double money;
    //从表实体应该包含主表实体的对象引用
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
}
<?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.mybatis.dao.IAccount">

<!--    定义封装account和user的resultMap-->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
<!--        一对一关系映射,配置封装user内容   javaType:内容封装提示(应该封装到哪里,不写会包空指针异常)-->
        <association property="user" column="uid" javaType="user">
            <id property="id" column="id"></id>
            <result property="username" column="username"></result>
            <result property="birthday" column="birthday"></result>
            <result property="sex" column="sex"></result>
            <result property="address" column="address"></result>
        </association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap">
        select u.*,a.id as aid,a.uid,a.money from account a,user u where a.uid = u.id;
    </select>
</mapper>
   /**
     * 账户查询所有
     */
    @Test
    public void TestFindAll_Account(){
        List<Account> accounts = mapper2.findAll();
        for (Account account:
                accounts) {
            System.out.println(account);
            System.out.println(account.getUser());
        }
    }
  • 多对多
/*1.建立两张表:用户表、角色表
         让用户表和角色表具有多对多的关系,需要使用中间表,中间表包含各自的主键,在中间表中是外键
*/
//user表已经建好

//创建角色表
CREATE TABLE `spring`.`role`(  
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  `role_name` VARCHAR(30),
  `role_desc` VARCHAR(60),
  PRIMARY KEY (`id`)
);
//创建中间表
CREATE TABLE `spring`.`user_role`(  
  `uid` INT(11) NOT NULL,
  `rid` INT(11) NOT NULL,
  PRIMARY KEY (`uid`, `rid`),
  FOREIGN KEY (`uid`) REFERENCES `spring`.`user`(`id`),
  FOREIGN KEY (`rid`) REFERENCES `spring`.`role`(`id`)
);


package com.mybatis.domain;

import java.io.Serializable;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/16 10:34
 */
public class Role  implements Serializable {
    private Integer roleId;
    private String roleName;
    private String roleDesc;

//    多对多关系映射:一个角色可以赋予多个用户
    private List<User> users;

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    public String getRoleDesc() {
        return roleDesc;
    }

    public void setRoleDesc(String roleDesc) {
        this.roleDesc = roleDesc;
    }

    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                ", roleDesc='" + roleDesc + '\'' +
                '}';
    }
}

package com.mybatis.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/10 17:54
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private String address;
    private String sex;
    private Date birthday;
    private List<Role> roles;

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    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;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", address='" + address + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}
<?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.mybatis.dao.IRoleDao">
    <resultMap id="roleMap" type="role">
        <id property="roleId" column="rid"></id>
        <result property="roleName" column="role_name"></result>
        <result property="roleDesc" column="role_desc"></result>
        <collection property="users" ofType="user">
            <id column="id" property="id"></id>
            <result property="username" column="username"></result>
            <result property="address" column="address"></result>
            <result property="sex" column="sex"></result>
            <result property="birthday" column="birthday"></result>
        </collection>
    </resultMap>

    <select id="findAll" resultMap="roleMap">
        <!--select * from role;-->
        <!--细节:当查询语句换行时前后加几个空格,防止拼接字符串时出现错误-->
       SELECT u.*,r.id AS rid,r.role_name,r.role_desc
        FROM role r
        LEFT OUTER JOIN user_role ur ON r.id = ur.rid
        LEFT OUTER JOIN user u ON u.id = ur.uid
   </select>
</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.mybatis.dao.IUserDao">

<!--    定义User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
        <collection property="roles" ofType="role">
            <id property="roleId" column="rid"></id>
            <result property="roleName" column="role_name"></result>
            <result property="roleDesc" column="role_desc"></result>
        </collection>
    </resultMap>
    <sql id="defualtSelect">
        select * from user;
    </sql>
    <select id="findAll" resultMap="userAccountMap">
<!--        <include refid="defualtSelect"></include>-->
        SELECT u.*,r.id AS rid,r.role_name,r.role_desc
         FROM USER u
         LEFT OUTER JOIN user_role ur ON u.id = ur.uid
         LEFT OUTER JOIN role r ON ur.rid = r.id;
    </select>

    <select id="findUserById" resultType="user" parameterType="Integer">
        select * from user where id = #{userId};
    </select>
</mapper>
package com.mybatis;

import com.mybatis.dao.IRoleDao;
import com.mybatis.dao.IUserDao;
import com.mybatis.domain.Role;
import com.mybatis.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.InputStream;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/11 9:56
 *
 *
 * 1.建立两张表:用户表、角色表
 *         让用户表和角色表具有多对多的关系,需要使用中间表,中间表包含各自的主键,在中间表中是外键
 * 2.建立两个实体类:用户实体类和角色实体类
 *          让用户和角色的实体类能体现出来多对多的关系
 *          各自包含对方一个集合引用
 * 3.建立两个配置文件
 *          用户的配置文件
 *          角色的配置文件
 * 4.实现配置:
 *          当我们查询用户时,可以同时得到用户所包含的角色信息
 *          当我们查询角色时,可以同时得到角色所赋予的用户信息
 */
public class MybatisTest {

    private InputStream in;
    private SqlSession session;
    private IUserDao userDao;
    private IRoleDao roleDao;

    @Before // 测试方法执行之前执行
    public void init() throws Exception{
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(in);
        session = factory.openSession(true);
        userDao = session.getMapper(IUserDao.class);
        roleDao = session.getMapper(IRoleDao.class);
    }
    @After //测试方法执行之后执行
    public void destroy() throws Exception{
        in.close();
    }
    /**
     * 用户查询所有
     */
    @Test
    public void TestFindAll_Role(){
        List<Role> roles = roleDao.findAll();
        for (Role role:
                roles) {
            System.out.println(role);
            System.out.println(role.getUsers());
        }
    }

    /**
     * 用户查询所有
     */
    @Test
    public void TestFindAll_User(){
            List<User> users = userDao.findAll();
            for (User user:
                 users) {
                System.out.println(user);
                System.out.println(user.getRoles());
            }
    }

}

第四篇 Mybatis的缓存和注解开发

  • Mybatis中的延迟加载

    • 问题:
      在一对多时,当我们有一个用户,他有100个账户。
      在查询用户时,是否要把关联的账户查出来? ×
      在查询账户时,是否要把关联的用户查出来?
    • 什么是延迟加载
      在真正使用数据时才发起查询,不用的时候不查询。按需加载(懒加载)
      • 如:在查询用户时,用户下的账户信息应该是,什么时候用,什么时候查
    • 什么是立即加载
      不管用不用,只要一调用方法,马上发起查询
      • 如:在查询账户时,账户所属的用户信息应该是,随着账户查询时一起查出来
    • 在对应的四种表关系中:
      • 一对多、多对多:通常使用延迟加载
      • 多对一、一对一:通常使用立即加载
  • 延迟加载示例

//首先要在主配置文件中打开延迟加载

    <settings>
<!--        开启Mybatis支持延迟加载-->
        <setting name="lazyLoadingEnabled" value="true"/>
      <setting name="aggressiveLazyLoading" value="false"/> <!--  (在 3.4.1 及之前的版本中默认为 true-->
    </settings>
  • 一对一:
<?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.mybatis.dao.IAccount">

<!--    定义封装account和user的resultMap-->
    <resultMap id="accountUserMap" type="account">
        <id property="id" column="id"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>
<!--        一对一关系映射,配置封装user内容
                javaType属性:内容封装提示(应该封装到哪里,不写会包空指针异常)
                select属性:指定的内容为查询用户的唯一标识
                column属性:用户根据id查询时,所需要的参数的值-->
        <association property="user" column="uid" javaType="user" select="com.mybatis.dao.IUserDao.findUserById"></association>
    </resultMap>
    <select id="findAll" resultMap="accountUserMap">
        select * from account
    </select>

    <select id="findAccountByUid" resultType="account">
        select * from account where uid = #{id}
    </select>
</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.mybatis.dao.IUserDao">

<!--    定义User的resultMap-->
    <resultMap id="userAccountMap" type="user">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result property="address" column="address"></result>
        <result property="sex" column="sex"></result>
        <result property="birthday" column="birthday"></result>
		<!--多对多关系映射-->
        <collection property="account" ofType="account" select="com.mybatis.dao.IAccount.findAccountByUid" column="id"></collection>
    </resultMap>

    <select id="findAll" resultMap="userAccountMap">
        select * from user
    </select>

    <select id="findUserById" resultType="user" parameterType="Integer">
        select * from user where id = #{userId};
    </select>
</mapper>
  • Mybatis中的一级缓存和二级缓存

    • 什么是缓存:
      存在于内存中的数据
    • 为什么使用缓存
      减少与数据库的交互,提高执行效率
    • 什么样的数据可以用缓存,什么样的数据不能用
      • 可以用
        经常查询并且不经常改变的
        数据的正确与否对最终结果影响不大的
      • 不可以用
        经常改变的数据
        数据的正确与否 对最终结果影响很大
        例如:商品的库存、银行的汇率、股市的牌价
  • 一级缓存

    它是指Mybatis中SqlSession对象的缓存
    当我们执行查询之后,查询的结果会同时存入到SQLSession为我们提供的一块区域中
    该区域的结构是一个Map。当我们再次查询同样的数据,Mybatis会先去SQLSession中查询是否有,有的话直接拿出来用
    当SqlSession对象消失时,Mybatis的一级缓存也会消失

    @Test
    public void TestFindUserById(){
        User user1 = mapper.findUserById(13);
        System.out.println(user1);
        User user2 = mapper.findUserById(13);
        System.out.println(user2);
        System.out.println(user1 == user2);

    }

运行结果:查询只进行了一次,说明第二次查询直接从SQLSession的缓存中得到的
在这里插入图片描述

//如果执行一次查询后关闭SQLSession对象并重新开启,结果便完全不一样

  @Test
    public void TestFindUserById(){
        User user1 = mapper.findUserById(13);
        System.out.println(user1);
//        session.close(); 二者皆可
        session.clearCache();
        session = factory.openSession(true);
        IUserDao mapper1 = session.getMapper(IUserDao.class);

        User user2 = mapper1.findUserById(13);
        System.out.println(user2);
        System.out.println(user1 == user2);

    }

运行结果:很明显,查询执行了两次,当SQLSession关闭后,缓存也随之消失
在这里插入图片描述
注意:当调用SQLSession的 增删改,commit(),close()等方法时,都会清空一级缓存

  • 二级缓存
    它指的是Mybatis中SQLSessionFactory对象的缓存,由同一个SQLSessionFactory对象创建的SQLSession共享其缓存
    在这里插入图片描述

二级缓存的使用步骤:
1. 让Mybatis框架支持二级缓存(在SqlMapConfig.xml即主配置文件中配置)
2.让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
3.让当前的操作支持二级缓存(在select标签中配置)

<!--    全局性地开启或关闭所有映射器配置文件中已配置的任何缓存。 默认值为 true-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

在这里插入图片描述

 @Test
    public void TestFindUserById(){
        SqlSession session1 = factory.openSession(true);
        IUserDao mapper = session1.getMapper(IUserDao.class);
        User user1 = mapper.findUserById(13);
        System.out.println(user1);
        session1.close();

        SqlSession session2 = factory.openSession(true);
        IUserDao mapper1 = session2.getMapper(IUserDao.class);
        User user2 = mapper1.findUserById(13);
        System.out.println(user2);
        session2.clearCache();

        System.out.println(user1 == user2);

    }

运行结果:很明显,只执行了一次查询,因为二级缓存中只存数据,所以每读一次都会讲数据赋给新的SQLSession对象
在这里插入图片描述

  • Mybatis的注解开发

    • 环境搭建
<?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.mybatis</groupId>
    <artifactId>day04_03annotation_mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.35</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version> 4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


</project>
package com.mybatis.domain;

import java.io.Serializable;
import java.util.Date;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/17 11:21
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;

    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;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
<!--主配置文件:SqlMapConfig.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="jdbcConfig.properties"></properties>
    <typeAliases>
        <package name="com.mybatis.domain"></package>
    </typeAliases>
    <environments default="mysql">
        <environment id="mysql">
            <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>
    <mappers>
        <package name="com.mybatis.dao"></package>
    </mappers>
</configuration>
##jdbcConfig.properties

driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/spring
username = root
password = 123456

##log4j.properties

# Global logging configuration
#设置全局的日志配置:输出到控制台
log4j.rootLogger = debug,console
# MyBatis logging configuration...
### 设置输出sql的级别,其中logger后面的内容全部为jar包中所包含的包名 ###
log4j.logger.org.apache=dubug
log4j.logger.java.sql.Connection=dubug
log4j.logger.java.sql.Statement=dubug
log4j.logger.java.sql.PreparedStatement=dubug
log4j.logger.java.sql.ResultSet=dubug
### 配置输出到控制台 ###
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern =  %d{ABSOLUTE} %5p %c{1}:%L - %m%n
  • 单表CRUD
package com.mybatis.dao;

import com.mybatis.domain.User;
import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/17 11:23
 *
 * 在 Mybatis中针对CRUD一共有四个注解
 *
 * @Select()
 * @Insert()
 * @Update()
 * @Delete()
 */

public interface IUserDao {

    @Select("select * from user")
    List<User> findAll();

    @Insert("insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})")
    void saveUser(User user);

    @Update("update user set username = #{username},birthday = #{birthday},sex = #{sex},address = #{address} where id = #{id}")
    void updateUser(User user);

    @Delete("delete from user where id = #{id}")
    void deleteUser(Integer id);
}

package com.mybatis.test;

import com.mybatis.dao.IUserDao;
import com.mybatis.domain.User;
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.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/17 11:36
 */
public class MybatisAnnoTest {

    private InputStream in;
    private SqlSessionFactory factory;
    private SqlSession session;
    private IUserDao userDao;

    @Before
    public void init() throws IOException {
         in = Resources.getResourceAsStream("SqlMapConfig.xml");
         factory = new SqlSessionFactoryBuilder().build(in);
         session = factory.openSession(true);
         userDao = session.getMapper(IUserDao.class);
    }
    @After
    public void destroy() throws IOException {
        session.close();
        in.close();
    }

    @Test
    public void TestFindAll() throws IOException {

        List<User> users = userDao.findAll();
        for (User user:users
             ) {
            System.out.println(user);
        }
    }

    @Test
    public void TestSaveUser() throws IOException {
        User user = new User();
        user.setUsername("东方老赢");
        user.setSex("女");
        user.setBirthday(new Date());
        user.setAddress("烟台莱阳");

        userDao.saveUser(user);
    }

    @Test
    public void TestUpdateUser() throws IOException {
        User user = new User();
        user.setId(1);
        user.setUsername("东方老王");
        user.setSex("男");
        user.setBirthday(new Date());
        user.setAddress("山东日照");

        userDao.updateUser(user);
    }


    @Test
    public void TestdeleteUser() throws IOException {
        userDao.deleteUser(18);
    }
}

细节:如果出现实体类与数据库表中的字段名不匹配,需要起别名,则可以这样
在这里插入图片描述

  • 多表查询

    • 一对一:
package com.mybatis.domain;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/18 9:38
 */
public class Account {
    private Integer id;
    private Integer uid;
    private Double money;

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getId() {
        return id;
    }

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

    public Integer getUid() {
        return uid;
    }

    public void setUid(Integer uid) {
        this.uid = uid;
    }

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", uid=" + uid +
                ", money=" + money +
                '}';
    }
package com.mybatis.dao;

import com.mybatis.domain.Account;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;

import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/18 9:40
 */
public interface IAccount {

    @Results(id = "resultMap",value = {
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "uid",property = "uid"),
            @Result(column = "money",property = "money"),
            @Result(property = "user",column = "uid",one = @One(select = "com.mybatis.dao.IUserDao.findUserById",fetchType = FetchType.EAGER))
    })
    @Select("select * from account")
    List<Account> findAll();
}
  @Test
    public void TestFindAll() throws IOException {

        List<Account> users = userDao.findAll();
        for (Account user:users
             ) {
            System.out.println(user);
            System.out.println(user.getUser());
        }
    }

运行结果:
在这里插入图片描述

  • 一对多
package com.mybatis.domain;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/17 11:21
 */
public class User implements Serializable {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    private List<Account> accounts;

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }

    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;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", birthday=" + birthday +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.mybatis.dao;

import com.mybatis.domain.User;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;

import java.util.List;

/**
 * @Author: 东方老赢
 * @Date: 2020/4/17 11:23
 *
 * 在 Mybatis中针对CRUD一共有四个注解
 *
 * @Select()
 * @Insert()
 * @Update()
 * @Delete()
 */

public interface IUserDao {
    @Results(id = "resultMap",value = {
           @Result(id = true,column = "id",property = "id"),
           @Result(column = "username",property = "username"),
           @Result(column = "birthday",property = "birthday"),
           @Result(column = "sex",property = "sex"),
           @Result(column = "address",property = "address"),
            @Result(property = "accounts",column = "id",many = @Many(select = "com.mybatis.dao.IAccount.findUserByUid",fetchType = FetchType.LAZY))
    })

    @Select("select * from user")
//    @ResultMap(value = "resultMap")
    List<User> findAll();

}

 @Test
    public void TestFindAll() throws IOException {

        List<User> users = userDao.findAll();
        for (User user:users
             ) {
            System.out.println(user);
            System.out.println(user.getAccounts());
        }
    }

运行结果:
在这里插入图片描述

  • 缓存的配置
    • 一级缓存
      注解的一级缓存是默认开启的,因此无需配置直接使用即可
      在这里插入图片描述 在这里插入图片描述
    • 二级缓存
      二级缓存也很简单,只需要加上一句注解即可
      在这里插入图片描述 在这里插入图片描述
      运行结果:在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_40181435/article/details/105387964
今日推荐