框架学不懂?超详细的框架讲解第一期:mybatis框架,四天完成,带你轻松入门

mybatis框架

mybatis框架的第一天: ①mybatis 的入门②mybatis的概述③mybatis入门案例④自定义mybatis框架(主要的目的是为了让大家了解Mybatis中的执行细节)

mybatis框架的第二天: ①mybatis 的单表crud操作②mybatis的参数和返回值设置③mybatis的dao编写④mybatis配置的细节(讲解几个标签的使用)

mybatis框架的第三天: ①mybatis 的深入和多表②mybatis的连接池③mybatis的事务控制及设计的方法④mybatis的多表查询
一对多(多对一)多对多

mybatis框架的第四天: ①mybatis 的缓存和注解开发②mybatis中的加载时机(查询时机)③mybatis的一级缓存和二级缓存④mybatis的注解开发:单表CRUD和多表查询

=========================================
写在开始之前:

maven工具如果打开别人的代码报错,依赖导不进去,一定要看一下你的仓库那些是否配置正确了。如果注解报错,一定要重新导一下。当然,你也可以采用复制粘贴的形式,把工程里的文件按全部拷贝到你的新创建的文件夹中去。

1.什么是框架?
它是我们项目开发中的一套解决方案。不同的框架解决的是不同的问题。使用框架的好处,就是框架封装了很多的细节,使得开发者可以使用极简的方式实现功能,大大提高开发效率。
2.三层架构
表现层:是用于展示数据的
业务层:是处理业务需求
持久层:是和数据库交互的
在这里插入图片描述
3.持久层技术解决方案
JDBC技术:Connection、PreparedStatement、 ResultSet
Spring的JdbcTemplate:Spring中对jdbc的简单封装
Apache的DBUtils:它和Spring的JdbcTemplate很像,也是对Jdbc的简单封装。
以上这届都不是框架。JDBC是规范。Spring的JdbcTemplate和Apache的DBUtils都只是工具类。

=========================================

一、Mybatis第一天

1.mybatis的入门与概述

mybatis是一个持久层框架,用java编写的,它封装了jdbc操作的很多细节,使开发者只需要关注sql本身,而无需关注注册驱动,创建链接等繁杂过程,它使用了ORM思想实现了结果集的封装。

ORM: Object Relation Mapping 对象关系映射。简单的说,就是把数据库表和实体类以及实体类的属性对应起来,让我们可以操作实体类就实现操作数据库表。

数据库字段javaBean
userUser
iduserId
user_nameuserName

2.mybatis的入门案例

2.1mybatis的环境搭建

环境搭建的步骤
第一步:创建maven工程并导入坐标
第二步:创建实体类和dao接口
第三步:创建Mybatis的主配置文件->SqlMapConfig.xml
第四步:创建映射配置文件->IUserDao.xml
环境搭建的注意事项
①创建IUserdDao.xml和IUserDao.java时,名称是为了和我们之前的知识保持一致。在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper。所以:IUserDao和IUserMapper是一样的。
②在idea中创建目录的时候,它和包是不一样的。包在创建时:com.itheima.dao是三级结构。目录在创建时,com.itheima.dao是一级结构。所以一定要一级一级的创建!
③mybatis的映射配置文件位置必须和dao接口的包的结构相同。
④映射配置文件的mapper标签的namespace属性的取值必须是dao接口的全限定类名
⑤映射配置文件的操作配置(select)id属性的取值必须是dao接口的方法名。

***当我们遵从了第3,4,5点之后,我们在开发中就无需再写dao的实现类。
创建Maven工程
打开idea工具->创建一个Maven工程->选择一个普通的web工程->考虑到基础阶段的演示,不勾选Create from archetype ->GroupId:com.itheima /AritactId:day01_eesy_mybatis/Version:1.0->创建完成

创建数据库

DROP TABLE IF EXISTS `user`;

CREATE TABLE `user` (
  `id` int(11) NOT NULL auto_increment,
  `username` varchar(32) NOT NULL COMMENT '用户名称',
  `birthday` datetime default NULL COMMENT '生日',
  `sex` char(1) default NULL COMMENT '性别',
  `address` varchar(256) default NULL COMMENT '地址',
  PRIMARY KEY  (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

insert  into `user`(`id`,`username`,`birthday`,`sex`,`address`) values 
(41,'老王','2018-02-27 17:47:08','男','北京'),
(42,'小二王','2018-03-02 15:09:37','女','北京金燕龙'),
(43,'小二王','2018-03-04 11:34:34','女','北京金燕龙'),
(45,'传智播客','2018-03-04 12:04:06','男','北京金燕龙'),
(46,'老王','2018-03-07 17:37:26','男','北京'),
(48,'小马宝莉','2018-03-08 11:44:00','女','北京修正');

导入Maven依赖

<groupId>com.lihao</groupId>
    <artifactId>day01_eesy_mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>


    <dependencies>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.10</version>
        </dependency>

    </dependencies>

按如下格式建类和包
在这里插入图片描述
接口

package com.lihao.dao;

import com.lihao.domain.User;

import javax.jws.soap.SOAPBinding;
import java.util.List;

/**
 * @author lhstart
 * @create 2021-11-01-20:47
 *
 * 用户的持久层接口
 */
public interface IUserDao {

    /**
     * 查询所有操作
     */

    List<User> findAll();
}

public class User implements Serializable {
	注意提供构造器、get和set方法、和toString方法。
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    }

创建SqlMapConfig.xml配置文件,注意这个文件的位置是在main/resoucrces包下,同时注意再同位置处,导入log4j.properties配置文件。

<?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>
    <!--配置mybatis的环境-->
    <environments default="mysql">
        <!--配置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/eesy_mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="041811"/>
            </dataSource>
        </environment>
    </environments>


    <mappers>
        <!--告知mybatis映射配置文件的位置-->
        <mapper resource="com/lihao/dao/IUserDao.xml"></mapper>
    </mappers>
</configuration>

创建映射配置文件IUserdao.xml文件,文件的地址是resource="com/lihao/dao/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">
        namespace方法用于确定该方法是在哪个接口中的。
<mapper namespace="com.lihao.dao.IUserDao">
		id指定的是方法名。
    <select id="findAll" resultType="com.lihao.domain.User">
        select  * from user;
    </select>
</mapper>
2.2mybatis的入门案例
package com.lihao.dao;
 import com.lihao.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 lhstart
 * @create 2021-11-02-10:50
 */
public class MybatisTest {
    public static void main(String[] args) throws Exception{
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessinFactory工厂
        SqlSessionFactoryBuilder factoryBuilder=new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory= factoryBuilder.build(in);
        //3.使用工厂生产SqlSession对象
        SqlSession session=sessionFactory.openSession();
        //4.通过session对象创建Dao接口的代理对象
        IUserDao  userDao = session.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        //6.遍历
        for (User user : users) {
            System.out.println(user);
        }
        //7.释放资源
        session.close();
        in.close();
    }
}

mybatis入门案例:
①读取配置文件
②创建sqlSessionFactory工厂
③创建sqlSession
④通过sqlSession创建DAO接口的代理对象
⑤通过DAO接口的代理对象调用方法
⑥关闭资源

注意事项: 不要忘记在映射配置中告知mybatis要封装到哪个实体类中,配置的方式:指定实体类的全限定类名。

mybatis基于注解的入门案例:
①把IUserDao.xml移除,在dao接口的方法上使用@Select注解,并且指定Sql语句。
②在SqlMapConfig.xml中的mapper配置时,使用class属性指定dao接口的全限定类名。
在这里插入图片描述

明确:我们在实际开发中,越简便越好,所以都是采用不写dao实现类的方式,但是mybatis是支持写dao实现类的。

2.3 mybatis入门案例的设计模式分析:在这里注意一下路径是如何加载的

通常情况下,在开发阶段,我们用两种方式书写路径。
①使用类加载器,它只能读取类路径的配置文件
②使用servletContext对象的getRealPath()
在这里插入图片描述

2.自定义mybatis的分析

2.1mybatis 在使用代理dao的方式实现增删改查时做什么事呢?

只有两件事:①创建代理对象②在代理对象中调用selectList.
在这里插入图片描述

2.2通过入门案例看到的类

class Resources
class SqlSessionFactoryBuilder
interface SqlSessionFactory
interface SqlSession

2.3自定义Mybatis类的实现

删除依赖
将以下依赖删除

       <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.5</version>
        </dependency>

根据删除依赖中所爆红的问题,进行类的创建和方法的创建
class Resources
class SqlSessionFactoryBuilder
interface SqlSessionFactory
interface SqlSession
注意把xml文件中爆红的约束删掉

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<!--配置mybatis的环境-->
<environments default="mysql">
    <!--配置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/eesy_mybatis"/>
            <property name="username" value="root"/>
            <property name="password" value="041811"/>
        </dataSource>
    </environment>
</environments>


<mappers>
    <!--告知mybatis映射配置文件的位置-->
    <mapper resource="com/lihao/dao/IUserDao.xml"></mapper>
</mappers>
</configuration>
<?xml version="1.0" encoding="UTF-8"?>
<mapper namespace="com.lihao.dao.IUserDao">
    <select id="findAll" resultType="com.lihao.domain.User">
        select  * from user;
    </select>
</mapper>

设置当前目录结构,并完成相关代码编写。
在这里插入图片描述

二、Mybatis第二天

2.1 回顾mybatis的自定义再分析和环境搭建+完善关于注解的mybatis

在这里插入图片描述

2.2 mybatis的crud(基于代理dao的方式)

进行crud操作的注意事项:
①在保存用户操作的过程中,需要注意:
(1)标签是insert 不是select 这是因为是保存用户。
(2)存在占位符的情况下,需要使用#{} 这一方式进行参数的获取。
(3)注意,参数获取实体类的属性是在parameterType属性中获取的,parameterType的属性值是实体类的全限定类名。
(4)如果类User中的属性的get/set方法是鼠标右键自动生成的,那么你可以采用#{username},#{address},…,等方式。大括号里面的是实体类的属性名。他可以通过反射的思想拿到User的属性值。
(5)如果你不是自动生成的,而是手写的。那么大括号里面的是get后面的名称。
(6)在Insert into User里面的username ,address等,这些是数据库中的字段名。
(7)在完成之后,需要提交事务。session.commit();

在这里由于都是右键生成的,所以我们可以进行如下所示的操作。
在这里插入图片描述

②在删除用户操作的过程中,需要注意:
(1)parameterType是interger类型。
(2)大括号里面的写什么都可以,因为它指的是一个整数类型的值。当parameterType是一个基本类型或者是一个基本类型包装类的参数且只有一个地方要写时,可以随意写。
在这里插入图片描述
③根据用户信息模糊查询:
在这里需要注意的是,测试模糊查询操作的过程中,需要加上%完成测试。
在这里插入图片描述
在这里插入图片描述
除此之外,还提供了另外一种完成模糊查询的方式:
在这里插入图片描述
使用 ‘%${value}%’ 的方式可以进行模糊查询。这样就不用写%王%了,只写王就可以了。

第一个方法是采用preparedstatement的参数占位符完成的查询,第二个方法是采用statement对象的字符串拼接SQL完成的,不言而喻,第一种方法常用。

如果

2.2.1 使用mybatis框架实现数据保存操作。–延续mybatis入门

1.实现接口的完善:

/**
 * @author lhstart
 * @create 2021-11-01-20:47
 *
 * 用户的持久层接口
 */
public interface IUserDao {

    /**
     * 查询所有操作
     */

    List<User> findAll();

    /**
     * 实现用户保存操作
     */
    void saveUser(User user);
}

2.修改映射配置文件:

<mapper namespace="com.lihao.dao.IUserDao">
    <!-- resultType表示返回值类型,查到的数据的返回值类型自然是User-->
    <select id="findAll" resultType="com.lihao.domain.User">
        select  * from user;
    </select>
    <!-- parameterType表示使用User类型的参数,#{}表示属性名。-->
    <insert id="saveUser" parameterType="com.lihao.domain.User">
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});
    </insert>
</mapper>

3.修改test测试类:

public class MybatisTest {
    //将这三个变量全部提取出来便于使用。
    private InputStream in;
    private SqlSession session;
    private IUserDao userDao;

    //为了使得代码过程便于简单书写,提取出如下的形式:
    @Before //在方法前执行
    public void init() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessinFactory工厂
        SqlSessionFactoryBuilder factoryBuilder=new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory= factoryBuilder.build(in);
        //3.使用工厂生产SqlSession对象
        session=sessionFactory.openSession();
        //4.通过session对象创建Dao接口的代理对象
        userDao = session.getMapper(IUserDao.class);


    }

    @After //在方法后执行
    public void destroy() throws Exception{
        //注意!!! 一定要提交事务!
        session.commit();
        //释放资源
        session.close();
        in.close();
    }

    @Test
    //对查询方法进行测试
    public void testFindAll() throws Exception{
        //使用代理对象执行方法
        List<User> users = userDao.findAll();
        //遍历
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    //对保存方法进行测试
    public void testSaveUser() throws Exception{
        User user = new User();
        user.setUsername("王伟");
        user.setAddress("新华区");
        user.setSex("男");
        user.setBirthday(new Date());

        userDao.saveUser(user);
    }



}
2.2.2 使用mybatis框架实现数据修改和删除操作。

1.实现接口的完善:

public interface IUserDao {

    /**
     * 查询所有操作
     */

    List<User> findAll();

    /**
     * 实现用户保存操作
     */
    void saveUser(User user);

    /**
     * 实现用户修改操作
     * @param user
     */
    void updateUser(User user);

    /**
     * 实现用户删除操作
     */
    void deleteUserById(Integer userId);
}

2.修改映射配置文件:

<?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属性表示接口名,id表示该接口下的方法.-->
<mapper namespace="com.lihao.dao.IUserDao">
    <!-- resultType表示返回值类型,查到的数据的返回值类型自然是User-->
    <select id="findAll" resultType="com.lihao.domain.User">
        select  * from user;
    </select>
    <!-- parameterType表示使用User类型的参数,#{}表示属性名。-->
    <insert id="saveUser" parameterType="com.lihao.domain.User">
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});
    </insert>

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

    <!--删除用户-->
    <delete id="deleteUserById" parameterType="Integer">
        delete from user where id=#{uid};
    </delete>
</mapper>

3.进行测试

public class MybatisTest {
    //将这三个变量全部提取出来便于使用。
    private InputStream in;
    private SqlSession session;
    private IUserDao userDao;

    //为了使得代码过程便于简单书写,提取出如下的形式:
    @Before //在方法前执行
    public void init() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessinFactory工厂
        SqlSessionFactoryBuilder factoryBuilder=new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory= factoryBuilder.build(in);
        //3.使用工厂生产SqlSession对象
        session=sessionFactory.openSession();
        //4.通过session对象创建Dao接口的代理对象
        userDao = session.getMapper(IUserDao.class);


    }

    @After //在方法后执行
    public void destroy() throws Exception{
        //注意!!! 一定要提交事务!
        session.commit();
        //释放资源
        session.close();
        in.close();
    }

    @Test
    //对查询方法进行测试
    public void testFindAll() throws Exception{
        //使用代理对象执行方法
        List<User> users = userDao.findAll();
        //遍历
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    //对保存方法进行测试
    public void testSaveUser() throws Exception{
        User user = new User();
        user.setUsername("王伟");
        user.setAddress("新华区");
        user.setSex("男");
        user.setBirthday(new Date());

        userDao.saveUser(user);
    }

    @Test
    public void testUpdateUser() throws Exception{
        User user = new User();
        user.setUsername("update d123伟");
        user.setAddress("新华区");
        user.setSex("男");
        user.setBirthday(new Date());

        //对应id
        user.setId(52);

        userDao.updateUser(user);
    }

    @Test
    public void testDeleteUser() throws Exception{
        userDao.deleteUserById(51);
    }



}

2.2.3 使用mybatis框架实现模糊查询、单行查询和返回一行一列查询的操作

1.实现接口的完善:

public interface IUserDao {

    /**
     * 查询所有操作
     */

    List<User> findAll();

    /**
     * 实现用户保存操作
     */
    void saveUser(User user);

    /**
     * 实现用户修改操作
     * @param user
     */
    void updateUser(User user);

    /**
     * 实现用户删除操作
     */
    void deleteUserById(Integer userId);

    /**
     * 实现用户查询一个的操作
     * @param id
     * @return
     */
    User findUserById(Integer id);

    /**
     * 实现用户模糊查询的操作
     */
    List<User> findUserByName(String name);

    /**
     * 实现一行一列的查询操作
     */
    Integer selectCount();

}

2.修改映射配置文件

<?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属性表示接口名,id表示该接口下的方法.-->
<mapper namespace="com.lihao.dao.IUserDao">
    <!-- resultType表示返回值类型,查到的数据的返回值类型自然是User-->
    <select id="findAll" resultType="com.lihao.domain.User">
        select  * from user;
    </select>
    <!-- parameterType表示使用User类型的参数,#{}表示属性名。-->
    <insert id="saveUser" parameterType="com.lihao.domain.User">
        insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address});
    </insert>

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

    <!--删除用户-->
    <delete id="deleteUserById" parameterType="Integer">
        delete from user where id=#{uid};
    </delete>
    
    <!--单行查询-->
    <select id="findUserById" parameterType="Integer" resultType="com.lihao.domain.User">
        select * from user where id=#{uid};
    </select>
    
    <!--模糊查询-->
    <select id="findUserByName" parameterType="String" resultType="com.lihao.domain.User">
        select * from user where username like #{name};
    </select>

    <!--返回一行一列的查询(数量查询)-->
    <select id="selectCount" resultType="Integer">
        select count(id) from user
    </select>
</mapper>

3.测试代码

package com.lihao.dao;
 import com.lihao.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 lhstart
 * @create 2021-11-02-10:50
 */
public class MybatisTest {
    //将这三个变量全部提取出来便于使用。
    private InputStream in;
    private SqlSession session;
    private IUserDao userDao;

    //为了使得代码过程便于简单书写,提取出如下的形式:
    @Before //在方法前执行
    public void init() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessinFactory工厂
        SqlSessionFactoryBuilder factoryBuilder=new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory= factoryBuilder.build(in);
        //3.使用工厂生产SqlSession对象
        session=sessionFactory.openSession();
        //4.通过session对象创建Dao接口的代理对象
        userDao = session.getMapper(IUserDao.class);


    }

    @After //在方法后执行
    public void destroy() throws Exception{
        //注意!!! 一定要提交事务!
        session.commit();
        //释放资源
        session.close();
        in.close();
    }

    @Test
    //对查询方法进行测试
    public void testFindAll() throws Exception{
        //使用代理对象执行方法
        List<User> users = userDao.findAll();
        //遍历
        for (User user : users) {
            System.out.println(user);
        }
    }

    @Test
    //对保存方法进行测试
    public void testSaveUser() throws Exception{
        User user = new User();
        user.setUsername("王伟");
        user.setAddress("新华区");
        user.setSex("男");
        user.setBirthday(new Date());

        userDao.saveUser(user);
    }

    @Test
    //对修改方法进行测试
    public void testUpdateUser() throws Exception{
        User user = new User();
        user.setUsername("update d123伟");
        user.setAddress("新华区");
        user.setSex("男");
        user.setBirthday(new Date());

        //对应id
        user.setId(52);

        userDao.updateUser(user);
    }

    @Test
    //对删除方法进行测试
    public void testDeleteUser() throws Exception{
        userDao.deleteUserById(51);
    }

    @Test
    //对返回一行一列方法进行测试
    public void testFindById() throws Exception{
        System.out.println(userDao.findUserById(41));
    }

    @Test
    //对模糊查询方法进行测试
    public void testFindByName() throws Exception{
        System.out.println(userDao.findUserByName("%王%"));
    }

    @Test
    //对数量方法测试
    public void testSelectCount()throws Exception{
        System.out.println("目前的数量是:"+userDao.selectCount());
    }


}
2.2.4 保存操作的细节–获取保存操作的id

如图所示,在正常情况下,我们是无法从保存之后的id中获取到id值的,这是因为在mysql中,Id值是自增的。那么如何获取保存操作之后的id值呢?
在这里插入图片描述
使用如下方法就可以获取了。
在这里插入图片描述

2.3mybatis中的参数深入以及结果集的深入

2.3.1 parameterType(输入类型)

传递简单类型
传递pojo对象 mybatis使用ognl表达式解析对象字段的值,#{} 或者${}括号中的值为pojo属性名称。
OGNL表达式: Object Graphic Navigation Language对象 图 导航 语言。它是通过对象的取值方法来获取数据,在写法上把get给省略了。比如:我们获取用户的名称,在类中的写法:user.getUsername();ONGL表达式的写法则是user.username,那么在Mybatis中为什么能直接写username,而不用user呢?这是因为在parameterType中已经提供了属性所属的类,所以此时不需要写对象名。
传递pojo包装类对象->在开发中经常会用到

=========================================
举例:
在这里插入图片描述

在这里插入图片描述
我们可以使用QueryVo中的属性作为查询条件进行查询。
在这里插入图片描述
在这里插入图片描述
//====================================

2.3.2 resultType(输出类型)

输出简单类型

输出pojo对象(查询一个)

如果User类的属性名发生改变(指和数据库字段名不一致),那么如何实现增删改查?
举例:
在这里插入图片描述
对于增删改方面:
将IUserDao.xml中的#{}中的内容进行修改,如:#{address}改为#{userAddress},确保能够找到对应的属性,完成封装。将属性类封装到数据库中。同时注意把saveUser中的keyProperty属性值id改为userId;这样就实现了增删改。
对于查询方面:
如何使得数据库将数据封装进属性类中去?经过查询,发现:
在这里插入图片描述
出现这种情况的原因是:
①由于mysql数据库在windows系统下不区分大小写,所以能够将userName属性封装进类中去,但是其余的属性对应不上。
在这里插入图片描述
所以其余的属性为null。如果使用linux系统,mysql数据库则严格区分大小写。
解决这个问题有两个思路:
①起别名
将select * from user;语句修改为
select id as userId, username as userName,address as userAddress, sex as userSex, birthday as userBirthday from user;

这样就保持列名一致了。可以将数据封装进去。

②mybatis采用配置的方式解决。配置查询结果的列名和实体类的属性名的对应关系保持一致。
(1)配置:配置查询结果的列名和实体类的属性名之间的对应关系。注意id可以随便取。type表示实体类。peoperty表示实体类属性名,column表示数据库列名
在这里插入图片描述
(2)在该引用的地方进行引用,如何引用?把resultType修改为resultMap:注意resultMap的值要和上面的id保持一致,才能达到引用效果。
在这里插入图片描述
//=============================================
总结:这两种方式各有利弊。方式一:读取快,方式二:开发效率高,可以引用。

2.4mybatis中的配置(主配置文件:sqlMapConfig.xml和一些标签)

SqlMapConfig.xml中配置的内容和顺序:

<configuration>
-properties(属性)
   --property
-settings(全局配置参数)
   --setting
-typeAliases(类型别名)
   --typeAlias
   --package
-typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
  --environment(环境子属性对象)
    ---transactionManager(事务管理)
    ---dataSource(数据源)
-mappers(映射器)
  --mapper
  --package
  </configuration>
2.4.1 properties标签的使用及细节

第一种使用properties属性的方式
这种配置方式是在sqlMapConfig.xml的内部进行配置。然后在dataSource标签中引用上面的配置。

<properties>
<property name="jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="jdbc.url" value="jdbc:mysql://localhost:3306/eesy_mybatis"/>
<property name="jdbc.username" value="root"/>
<property name="jdbc.password" value="041811"/>
</properties>
<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>

第二种使用properties属性的方式
1.在类路径下定义db.properties文件
类路径的意思如图所示,指的是log4j和sqlMapConfig.xml配置文件所在的位置。
在这里插入图片描述

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/eesy_mybatis
jdbc.username=root
jdbc.password=041811

2.对properties标签进行配置

<!-- 配置连接数据库的信息
**分为两个属性,二选一即可。**
resource 属性:用于指定 properties 配置文件的位置,要求配置文件必须在类路径下
resource="jdbcConfig.properties"
url 属性:
URLUniform Resource Locator 统一资源定位符
http://localhost:8080   /mystroe/CategoryServlet URL
协议       主机    端口   URI
URI:Uniform Resource Identifier 统一资源标识符  这里指/mystroe/CategoryServlet
它是可以在 web 应用中唯一定位一个资源的路径。这个URL属性和mapper中的url属性一致。
-->
如:
<properties url=
file:///D:/IdeaProjects/day02_eesy_01mybatisCRUD/src/main/resources/jdbcConfig.prop
erties">
解析:file 协议
	 '///' 默认主机端口号
	 D:/...URI统一资源标识符
</properties>

使用时再次引用即可。

<dataSource type="POOLED">
<property name="driver" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</dataSource>

2.4.2 typeAliases标签的使用及细节

使用typeAliases配置别名,它只能配置domain类中的别名。

SqlMapConfig.xml 中配置:
<typeAliases>
<!-- 单个别名定义 -->
<typeAlias alias="user" type="com.itheima.domain.User"/>
<!-- 批量别名定义,扫描整个包下的类,别名为类名(首字母大写或小写都可以) -->
<package name="com.itheima.domain"/>
<package name="其它包"/>
</typeAliases>

举例:
在这里插入图片描述
在这里插入图片描述

*2.4.3 mappers标签的使用及细节

1.resource属性:

使用相对于类路径的资源,在xml的配置文件开发时使用
如:<mapper resource="com/itheima/dao/IUserDao.xml" />
注意配置文件是都存放在 main下的resources中的。

2.class属性:

使用 mapper 接口类路径,class属性用于注解开发时使用。
如:<mapper class="com.itheima.dao.UserDao"/>
注意:此种方法要求 接口名称和 mapper 映射文件名称(UserDao)相同,且在同一个目录中。 

3.package属性:

package标签用于指定dao接口所在的包,当指定了之后,就不需要再写mapper以及resource或者class了。注意:使用package标签时,必须要保证xml的文件名和接口名一致才行,否则就会报错!!!!!!!!!!!!!!!
注意红色和黄色都一致。
在这里插入图片描述

在这里插入图片描述

=========================================

三、Mybatis第三天

3.1mybatis中连接池的使用及事务控制(原理了解,应用会用)

3.1.1 连接池的概念引入

我们在实际开发中都会使用连接池。它可以减少获取连接的时间。连接池就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到同一连接。该集合还必须实现队列的特性,先进先出。

3.1.2 mybatis中的连接池

mybatis连接池提供了3种方式的配置:
配置的位置:
(1)主配置文件SqlMapConfig.xml中的dataSource标签,type属性表示采用何种连接池方式。type的取值有三种,分别是POLLED\UNPOLLED\JNDI

第一种是采用传统的javax.sql.Datasource规范中的连接池,mybatis中有针对规范的实现。
第二种采用传统的获取连接的方式,虽然也实现Javax.sql.DataSource接口,但是并没有使用池的思想。
第三种采用服务器提供的JNDI 技术实现,来获取DataSource对象,不同的服务器所能拿到的DataSource是不一样的。注意:**如果不是web或者maven的war工程,是不能使用的。**我们课程中使用的是tomcat服务器,采用连接池就是dbcp连接池。

为了便于对比,可以使用快捷键crtl+N进行搜索,找到对应的类。

对比unpooled和pooled的不同
在这里插入图片描述

我们找到了两个类,分别是unpooledDataSource 和pooledDataSource.经过观察,他们都实现了dataSource接口。在这个接口中,有一个getConnection方法。这样,我们分别去找unpooledDataSource和pooledDataSource这两个类的getConnection方法。
在unpooledDataSource中,有一个getConnection方法,这个方法返回了doGetConnection方法。这里面创建了props对象,并且把user和password传进去,并且注册驱动获取连接,并且把连接返回了。

在pooledDataSource中,有一个getConnection方法,这个方法返回了一个popConnection方法。
在pooledDataSource中具体实现的过程如下:
连接池分为两个:空闲池和活动池。如图所示,当我们要获取连接时,先从空闲池中获取连接,如果空闲池中有连接的话,就直接拿空闲池中的一个连接来用。如果空闲池中的连接已经没有了,那就看看活动池中的连接是否已经达到了最大数量。如果没有达到最大数量,那就再创建一个连接返回。如果已经达到了最大数量,那就判断这里面哪个是最先进来的,把它返回获取。我们再开发中使用pooled的思想。
在这里插入图片描述

3.1.3 mybatis中事务原理和自动提交设置

什么是事务?
事务的四大特性ACID
不考虑隔离性会产生的3个问题
解决办法:四种隔离级别
mybatis中的事务是通过sqlSession对象的commmit方法和rollback方法。

如何设置自动提交?
如图所示,直接把openSession中的参数设置为true即可.但是通常情况下不这么做。
在这里插入图片描述

3.2 mybatis中基于XML配置的动态SQL语句使用(会用即可)

mybatis的映射文件中,前面的SQL都是比较简单的,有些时候业务逻辑复杂时,我们的SQL是动态变化的,此时在前面的学习中我们的SQL就不能满足要求了。
案例:在实际开发过程中,用户传入的不知道是什么属性。

3.2.1 第一个例子:查询条件是用户名时=》if标签的用法

写接口方法
在这里插入图片描述
写xml映射配置文件
在这里插入图片描述
书写时的注意事项:
①方框框起来的都是sql语句,那么这个大小写是无关紧要的(sql语句在windows系统下不区分大小写),但是一定要注意#{}里面的内容和test里面的内容,必须严格区分大小写。因为这是user类的属性名。
②同时注意提供的参数是parameterType。
③注意返回的resultMap 是userMap 因为我们的实体类属性名和数据库字段名不一致。
注意加上and。必须是and
写测试代码
在书写测试代码时需要注意,username必须是精确匹配的。
在这里插入图片描述

3.2.2 第二个例子:查询条件是性别和用户名时=》where标签的用法

写xml映射配置文件
在这里插入图片描述
注意事项:and 加上如果不写where 1=1,那么你就应该用where标签替换where1=1.

测试代码
在这里插入图片描述

3.2.3 foreach标签的使用

1.补充IUserDao接口方法

/**
     * 根据queryvo提供的id集合,查询用户信息
     * @param queryvo
     * @return
     */
    List<User> findUserInIds(Queryvo queryvo);

2.给queryvo添加ids属性

public class Queryvo {

    private User user;
    private List<Integer> ids;

    public Queryvo() {
    }

    public Queryvo(User user, List<Integer> ids) {
        this.user = user;
        this.ids = ids;
    }

    public User getUser() {
        return user;
    }

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

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }

    @Override
    public String toString() {
        return "Queryvo{" +
                "user=" + user +
                ", ids=" + ids +
                '}';
    }
}

3.写xml映射配置文件
注意:foreach标签中 collection 属性值为ids 即为queryvo里面的属性 item为ids中的每一个值,separator表示用逗号分隔开。

<!-- 返回根据queryvo查询得到的用户实例-->
    <select id="findUserInIds" resultType="com.lihao.domain.User" parameterType="com.lihao.domain.Queryvo">
        select * from user
        <where>
            <if test="ids !=null and ids.size()>0">
                <foreach collection="ids" open="and id in(" close=")" item="uid" separator=",">
                    #{uid}
                </foreach>
            </if>
        </where>
    </select>

4.测试

@Test
    //对findUserInIds方法进行测试
    public void testfindUserInIds() throws Exception{
        Queryvo queryvo = new Queryvo();
        List<Integer> list = new ArrayList<Integer>();
        list.add(41);
        list.add(43);
        list.add(45);
        queryvo.setIds(list);


        List<User> userList=userDao.findUserInIds(queryvo);
        for (User user : userList) {
            System.out.println(user);
        }
    }

3.2.4 、sql标签的使用

注意,如果要是图片2的引用,一定不能加分号,因为这是拼接而成的sql语句。加了分号会报错。
在这里插入图片描述
图片2:
在这里插入图片描述

3.3 mybatis多表操作(**)重点

3.3.1 mybatis中的多表查询概述

表之间的常见关系有几种:
一对多
多对一
一对一
多对多

举例:
用户和订单就是一对多
订单和用户就是多对一
一个用户可以下多个订单
而多个订单则属于同一个用户

人和身份证号就是一对一
一个人之能有一个身份证号
一个身份证号只能属于一个人

老师和学生之间就是多对多
一个学生可以被多个老师教过
一个老师可以教多个学生

特例:
如果拿出每一个订单,他都只能属于一个用户。所以Mybatis就把多对一看成了一对一。

mybatis中的多表查询:
示例: 用户和账户
比如:一个用户可以有多个账户,但一个账户只能属于一个用户(多个账户也可以属于同一个用户)
步骤:
1.建立两张表:用户表,账户表
让用户表和账户表之间具备一对多的关系:需要使用外键在账户表中添加
2.建立两个实体类:用户实体类和账户实体类
让用户和账户的实体类能体现出来一对多的关系
3.建立两个配置文件:
用户的配置文件
账户的配置文件
4.实现配置:当我们查询用户时,可以同时得到用户下所包含的账户信息。当我们查询账户时,则可以得到账户所属的用户信息。

3.3.2 完成account表的建立及实现单表查询

1.给数据库添加账户表

DROP TABLE IF EXISTS `account`;

CREATE TABLE `account` (
  `ID` INT(11) NOT NULL COMMENT '编号',
  `UID` INT(11) DEFAULT NULL COMMENT '用户编号',
  `MONEY` DOUBLE DEFAULT NULL COMMENT '金额',
  PRIMARY KEY  (`ID`),
  KEY `FK_Reference_8` (`UID`),
  CONSTRAINT `FK_Reference_8` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;

INSERT  INTO `account`(`ID`,`UID`,`MONEY`) VALUES (1,46,1000),(2,45,1000),(3,46,2000);

2.创建idea工程,实现account的单表查询操作

写接口

public interface IAccountDao {
    /**
     * 查询账户所有操作
     */

    List<Account> findAccountAll();




    /**
     * 实现用户查询一个的操作
     * @param id
     * @return
     */
    Account findAccountById(Integer id);
}

写映射配置文件

<?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属性表示接口名,id表示该接口下的方法.-->
<mapper namespace="com.lihao.dao.IAccountDao">
    <!-- resultType表示返回值类型,查到的数据的返回值类型自然是User-->
    <select id="findAccountAll" resultType="Account">
        select  * from account;
    </select>

    <!--单行查询-->
    <select id="findAccountById" parameterType="Integer" resultType="Account">
        select * from account where id=#{uid};
    </select>

</mapper>

写测试方法

public class MybatisAccountTest {
    //将这三个变量全部提取出来便于使用。
    private InputStream in;
    private SqlSession session;
    private IAccountDao accountDao;

    //为了使得代码过程便于简单书写,提取出如下的形式:
    @Before //在方法前执行
    public void init() throws Exception{
        //1.读取配置文件
        in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessinFactory工厂
        SqlSessionFactoryBuilder factoryBuilder=new SqlSessionFactoryBuilder();
        SqlSessionFactory sessionFactory= factoryBuilder.build(in);
        //3.使用工厂生产SqlSession对象
        session=sessionFactory.openSession();
        //4.通过session对象创建Dao接口的代理对象
        accountDao = session.getMapper(IAccountDao.class);


    }

    @After //在方法后执行
    public void destroy() throws Exception{
        //注意!!! 一定要提交事务!
        session.commit();
        //释放资源
        session.close();
        in.close();
    }

    @Test
    //对查询方法进行测试
    public void testFindAll() throws Exception{
        //使用代理对象执行方法
        List<Account> accounts = accountDao.findAccountAll();
        for (Account account : accounts) {
            System.out.println(account);
        }
    }


    @Test
    //对返回一行一列方法进行测试
    public void testFindById() throws Exception{
        System.out.println(accountDao.findAccountById(1));
    }
}

3.3.3 完成account表的一对一操作(常用方式:建立实体类关系的方式)

1.在IAccountDao接口中完善如下方法,同时完善account类

/**
     * 实现一对一查询
     * 操作:跟据该方法查询所有账户,
     * 这个账户信息带有用户的所有信息
     */
    List<Account> findAccountUsernameAndAddress();
public class Account {
    private Integer id;
    private Integer uid;
    private Double money;


    //从表的实体类应该包含一个主表实体的对象引用
    private User user;
    //生成user的get和set方法
    public User getUser() {
        return user;
    }

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

2.在IAccountDao.xml文件中为findAccountUsernameAndAddress方法配置

<?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属性表示接口名,id表示该接口下的方法.-->
<mapper namespace="com.lihao.dao.IAccountDao">
    
<!--    定义封装account和user的resultMap-->
    <resultMap id="accountUserMap" type="account">
    property表示实体类名称 column表示数据库字段名
        <id property="id" column="aid"></id>
        <result property="uid" column="uid"></result>
        <result property="money" column="money"></result>


<!--        一对一的关系映射,配置封装user的内容-->
<!--        association中的property属性字段表示是在Account类里面的user类
						  column字段表示account和user两个实体类是通过什么连接的 
            			  javaType表示user类的返回值类型是user
    -->
        <association property="user" column="uid" javaType="user">

            <id property="id" column="id"></id>
            <result column="username" property="username"></result>
            <result column="address" property="address"></result>
            <result column="sex" property="sex"></result>
            <result column="birthday" property="birthday"></result>
        </association>
    </resultMap>
    
 
    <!-- resultType表示返回值类型,查到的数据的返回值类型自然是User-->
    <select id="findAccountAll" resultType="Account">
        select  * from account;
    </select>

    <!--单行查询-->
    <select id="findAccountById" parameterType="Integer" resultType="Account">
        select * from account where id=#{uid};
    </select>


    <!--查询所有用户信息,同时包含用户的所有信息 注意resultMap一定不能省略-->
    <select id="findAccountUsernameAndAddress" resultMap="accountUserMap">
        select u.*,a.id as aid ,a.uid,a.money from account a,user u where u.id = a.uid;
    </select>
</mapper>

3.完成测试代码的编写

@Test
    public void testfindAccountUsernameAndAddress () throws Exception{
        List<Account> accounts = accountDao.findAccountUsernameAndAddress();
        for (Account account : accounts) {
            System.out.println("---该账户的信息---");
            System.out.println(account);
            System.out.println(account.getUser());
        }


    }
3.3.3 完成user表的一对多操作(一个用户可以有多个账户信息)

1.分析sql语句:
一个人可以有多个账户,也可能没有帐户。使用左外连接。

SELECT u.*,a.id AS aid,a.`UID`,a.`MONEY` FROM USER u LEFT OUTER JOIN account a ON u.id = a.`UID`;

2.修改IUserDao和user类

/**
     * 查询所有用户信息,并返回用户信息下的账户信息
     */
    List<Account> findUserAccount();
public class User implements Serializable {

    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    //accounts属性表示user类的所有账户
    private List<Account> accounts;
    

    public User() {
    }

    public User(Integer id, String username, Date birthday, String sex, String address) {
        this.id = id;
        this.username = username;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
    }

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

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

3.编写userdao.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属性表示接口名,id表示该接口下的方法.-->
<mapper namespace="com.lihao.dao.IUserDao">


<!--    type表示配置的类-->
    <resultMap id="UserAccountMap" type="User">
        <id property="id" column="id"></id>
        <result property="username" column="username"></result>
        <result column="address" property="address"></result>
        <result column="sex" property="sex"></result>
        <result column="birthday" property="birthday"></result>

<!--        collection表示映射的集合 property 表示映射的集合属性
               ofType表示集合中的是什么属性
    -->
        <collection property="accounts" ofType="account">
            <id property="id" column="aid"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>


    <!-- resultType表示返回值类型,查到的数据的返回值类型自然是User-->
    <select id="findAll" resultType="com.lihao.domain.User">
        select  * from user;
    </select>

    <!--单行查询-->
    <select id="findUserById" parameterType="Integer" resultType="com.lihao.domain.User">
        select * from user where id=#{uid};
    </select>


<!--   实现用户下的账户查询 -->
    <select id="findUserAccount" 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>


</mapper>

4.测试代码

@Test
    //查询所有用户信息,并返回用户信息下的账户信息
    public void testFindUserAccount() throws Exception{
        for (User user : userDao.findUserAccount()) {
            System.out.println("---用户信息(包含账户信息)---");
            System.out.println(user);
            System.out.println(user.getAccounts());
        }

    }

总结一下:对于一对一查询和一对多查询,如何编写sql语句呢?方法是执行sql语句之后,表中是一条一条的数据,这一条的数据正好能够对应我们的实体类。这样才能够进行封装。对于本例的一对多查询来说,必须左联,因为每一条数据都得对应一个User类。如果出现一个user类有两个account账户时,即使这是两条数据也没有关系。

3.3.4 完成表的多对多操作

实例:用户和角色(用户可以有多个角色)一个角色可以赋予多个用户,所以用户和角色之间是多对多

步骤:①建立两张表:用户表,角色表
让用户表和角色表具有多对多的关系,需要使用中间表。中间表中包含各自的主键,也就是在中间表中是外键。
②建立两个实体类:用户实体类和角色实体类。让用户和角色的实体类能体现出多对多的关系。=》各自包含对方一个集合引用即可。
③建立两个配置文件:用户的配置文件和角色的配置文件。
④实现配置:当我们查询用户时,可以同时得到用户所包含的角色信息。当我们查询角色时,可以得到角色所包含的用户信息。

mysql语句的分析①:
在这里插入图片描述
这张图对应的mysql语句为:
在这里插入图片描述

mysql语句的分析②:
在这里插入图片描述
这张图对应的mysql语句为:
在这里插入图片描述

=========================================

四、Mybatis第四天

1.mybatis中的延迟加载
问题:在一对多中,当我们有一个用户,它有100个账户。

在查询用户的时候,要不要把关联的账户查出来?

在查询用户时,应该是什么时候使用什么时候查询的。

在查询账户的时候,要不要把关联的用户查出来?
在查询账户时,账户的所属用户信息应该是随着账户查询时,一起查询出来。

①什么是延迟加载:在真正使用数据时,才发起查询。不用的时候不查询,按需加载(懒加载)
②什么是立即加载:不管用不用,只要一调用方法,马上发起查询。

在对应的四种表关系中,有:一对多,多对一,一对一,多对多四种关系。
当面对多对一和一对一时,通常形况下我们都是采用立即加载
当面对一对多和多对多时,通常情况下我们都是采用延迟加载
2.mybatis中的缓存
①什么是缓存
存在于内存中的临时数据。
②为什么使用缓存
减少和数据库的交互次数,提高执行效率。
③什么样的数据能使用缓存,什么样的数据不能使用
适用于缓存:经常查询并且不经常改变的。数据的正确与否对最终结果影响不大的。
不适用于缓存:经常改变的数据或数据的正确与否对最终的结果影响很大的。例如:银行的汇率,股市的牌价。
④mybatis中的一级缓存和二级缓存
3.mybatis中的注解开发
①环境搭建
②单表CRUD操作(代理Dao方式)
③多表查询操作
④缓存的配置

4.1 mybatis一对一实现延迟加载

为了能够实现延迟加载,我们需要修改代码。经过观察,我们发现associtaion属性中,应该删除复杂的配置。因为配置延迟加载,再提供这些封装没有任何意义,因为如果不查数据是不可能封装的。那么,我们需要使用一个新的属性,这个属性是select。 select属性指定的内容是查询用户属性的唯一标志。也就是说在IUserDao.xml中根据id查询用户的那个配置。

<!--        一对一的关系映射,配置封装user的内容-->
<!--        association中的property属性字段表示是在Account类里面的user类
						  column字段表示account和user两个实体类是通过什么连接的 
            			  javaType表示user类的返回值类型是user
    -->
        <association property="user" column="uid" javaType="user">

        //    <id property="id" column="id"></id>
          //  <result column="username" property="username"></result>
           // <result column="address" property="address"></result>
            //<result column="sex" property="sex"></result>
            //<result column="birthday" property="birthday"></result>
        </association>
    </resultMap>

新的属性select
select 属性的内容是查询用户属性的唯一标志。这里的select是需要写全名的。它的全名是com.itheima.dao.IUserDao.findById方法。(也就是namespace加上这个方法的id。)同时注意还需要提供column属性。这个属性是uid。(uid是account中的属性,这个属性相当于findByid中的id参数,需要我们提供。)当我们这样写完之后,就相当于把用户信息也给提供过来了。
在这里插入图片描述
我们还需要注意我们提供的内容能不能和数据库对上,经过观察发现是没有问题的。所以,在这里,我们不需要提供resultMap.(这个方法是在IUserDao中的findById方法。)
在这里插入图片描述
测试:发现并没有实现延迟加载。一次查询直接全部加载出来了。
在这里插入图片描述
特别注意:需要配置如下:在主配置文件中开启Mybatis支持延迟加载。第二个setting 的name属性应该是false,否则便不能延迟加载(在3.4.1后的mybatis默认是false)
在这里插入图片描述

4.2 mybatis一对多实现延迟加载

思想:在用的时候,调用对方配置文件的一个配置来实现查询的功能。我们需要知道:①如何在配置文件中配置②主配置文件中的开启步骤。
1.给账户添加方法
在这里插入图片描述
2.修改userDAO.xml映射配置文件

<!-- 定义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集合的映射 注意:这个column字段是user的id,并不是uid!id被当作findAccountByUid的参数!-->
        <collection property="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
    </resultMap>

    <!-- 查询所有 -->
    <select id="findAll" resultMap="userAccountMap">
        select * from user
    </select>

3.修改Account.xml映射配置文件

 <!-- 根据用户id查询账户列表 ,返回值可以写成account的原因是实体类名和数据库字段名一致,不需要使用resultMap配置-->
    <select id="findAccountByUid" resultType="account">
        select * from account where uid = #{uid}
    </select>

4.测试延迟加载

    /**
     * 测试延迟加载
     */
    @Test
    public void testFindAll(){
        List<User> users = userDao.findAll();
//        for(User user : users){
//            System.out.println("-----每个用户的信息------");
//            System.out.println(user);
//            System.out.println(user.getAccounts());
//        }
    }

4.3 缓存

4.3.1 一级缓存测试

mybatis中的一级缓存
一级缓存:它指的是mybatis中SqlSession对象的缓存。当我们执行查询之后,查询的结果会同时存入到SqlSession为我们提供的一块区域中。该区域的结构是一个Map。当我们再次查询同样的数据,mybatis会先去sqlSession中查看是否有,有的话直接拿出来用。当sqlsession对象消失时,mybatis的一级缓存也就消失了。
在这里插入图片描述
经过测试之后,发现结果为true.
这两个user是一样的,所以说,第一次找时,这个对象在sqlSession中缓存起来了。
在这里插入图片描述
经过这次测试之后,发现结果为false。这是因为sqlSession中缓存的数据被删除了。除此之外,我们还可以采用如下方法清除缓存。
在这里插入图片描述

4.3.2 一级缓存的分析

在这里插入图片描述

4.3.3 二级缓存的分析

二级缓存:它指的是Mybatis中SqlSessionFactory对象的缓存。由同一个SqlSessionFacory对象船舰的SqlSession共享其缓存。
在这里插入图片描述
二级缓存的使用步骤:
第一步:让Mybatis框架支持二级缓存(在SqlMapConfig.xml中配置)
在这里插入图片描述

第二步:让当前的映射文件支持二级缓存(在IUserDao.xml中配置)
在这里插入图片描述

第三步:让select标签支持二级缓存(在操作中配置)
在这里插入图片描述

为什么配置了之后仍然发现有问题?原因是二级缓存中存放的内容是数据,而不是对象。当其余session找二级缓存中的数据时,会new 一个新的对象,二级缓存就把存放的内容注入进这个对象中去。
在这里插入图片描述

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值