用案例学习Mybatis总结

Mybatis学习总结

一、前言

以下内容均为观看传智播客Mybatis的个人总结,如有错误,欢迎指正。

二、什么是Mybatis

2.1 概述

mybatis是一个用java编写的持久层框架,它封装了jdbc操作的很多细节,使开发者只需要关注SQL语句本身,而无需关注注册驱动,创建连接等繁杂的过程;而且它实现了ORM(Object Relational Mappging 对象关系映射)思想的结果集封装。

2.2 执行流程

  • 加载配置并初始化

    • 触发条件:加载配置文件
    • 处理过程:将SQL的配置信息加载成为一个个MappedStatement对象(包括了传入参数映射配置、执行的SQL语句、结果映射配置),存储在内存中。
  • 接收调用请求

    • 触发条件:调用Mybatis提供的API
    • 传入参数:为SQL的ID和传入参数对象
    • 处理过程:将请求传递给下层的请求处理层进行处理。
  • 处理操作请求

    • 触发条件:API接口层传递请求过来
    • 传入参数:为SQL的ID和传入参数对象

三、Mybatis的入门

3.1 环境搭建

  • 准备数据库
CREATE DATABASE `mybatis`;
use `mybatis`;
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工程(创建过程略)
  • 导入坐标
<?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.itheima</groupId>
    <artifactId>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>
</project>

3.2 入门案例

  • 创建实体类
package com.itheima.domain;
public class User implements Serializable{
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
	...get()/set()/toString()...
}
  • 创建dao接口
public interface UserDao {
//    @Select("select * from user")
    List<User> findAll();
}
  • 创建Mybatis的主配置文件: SqlConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<!-- mybatis的主配置文件 -->
<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/mybatis"/>
                <property name="username" value="root"/>
                <property name="password" value="1234"/>
            </dataSource>
        </environment>
    </environments>
    <!-- 指定映射配置文件的位置,映射配置文件指的是每个dao独立的配置文件 -->
    <mappers>
        <!-- <mapper class="com.itheima.dao.IUserDao"/> -->
        <mapper resource="com/itheima/dao/IUserDao.xml"/>
    </mappers>
</configuration>
  • 创建映射配置文件: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">
<mapper namespace="com.itheima.dao.IUserDao">
    <!--配置查询所有-->
    <select id="findAll" resultType="com.itheima.domain.User">
        select * from user
    </select>
</mapper>
  • 创建测试类
package com.itheima.test;
public class MybatisTest {
    public static void main(String[] args)throws Exception {
        //1.读取配置文件
        InputStream in = Resources.getResourceAsStream("SqlMapConfig.xml");
        //2.创建SqlSessionFactory工厂
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = builder.build(in);
        //3.使用工厂生产SqlSession对象
        SqlSession session = factory.openSession();
        //4.使用SqlSession创建Dao接口的代理对象
        IUserDao userDao = session.getMapper(IUserDao.class);
        //5.使用代理对象执行方法
        List<User> users = userDao.findAll();
        for(User user : users){
            System.out.println(user);
        }
        //6.释放资源
        session.close();
        in.close();
    }
}

3.3 入门总结

  • 注意点

    第一个:创建IUserDao.xml 和 UserDao.java时名称是为了和我们之前的知识保持一致。
    在Mybatis中它把持久层的操作接口名称和映射文件也叫做:Mapper
    所以:IUserDao 和UserMapper是一样的
    第二个:在idea中创建目录的时候,它和包是不一样的
    包在创建时:com.itheima.dao它是三级结构
    目录在创建时:com.itheima.dao是一级目录
    第三个:mybatis的映射配置文件位置必须和dao接口的包结构相同
    第四个:映射配置文件的mapper标签namespace属性的取值必须是dao接口的全限定类名
    第五个:映射配置文件的操作配置(select),id属性的取值必须是dao接口的方法名

  • 基于注解的案例:

    • 只需要将USerDao与主配置文件中注释的部分取消。

3.4 自定义Mybatis

  • 流程分析

在这里插入图片描述

  • 读取配置文件,根据配置文件创建session工厂,创建session工厂使用了构建者模式。

Resource.java:

public class Resources {
    public static InputStream getResourceAsStream(String filePath){
        return Resources.class.getClassLoader().getResourceAsStream(filePath);
    }
}

SessionFactoryBuilder.java:

public class SqlSessionFactoryBuilder {
    public SqlSessionFactory build(InputStream cfg){
        Configuration configuration = XMLConfigBuilder.loadConfiguration(cfg);
        return new DefaultSqlSessionFactory(configuration);
    }
}

DefaultSqlSessionFactory.java

public class DefaultSqlSessionFactory implements SqlSessionFactory{
    private Configuration configuration;
    public DefaultSqlSessionFactory(Configuration configuration) {
        this.configuration = configuration;
    }
    @Override
    public SqlSession openSession() {
        return new DefaultSqlSession(configuration);
    }
}
  • 根据工厂创建session对象。

DefaultSqlSession.java

public class DefaultSqlSession implements SqlSession {
    private Configuration configuration;
    private Connection connection;
    public DefaultSqlSession(Configuration configuration) {
        this.configuration = configuration;
        connection = DataSourceUtil.getConnection(configuration);
    }
    @Override
    public <T> T getMapper(Class<T> daoInterfaceClass) {
        return (T) Proxy.newProxyInstance(daoInterfaceClass.getClassLoader(),new Class[]{daoInterfaceClass},new MapperProxy(configuration.getMappers(),connection));
    }
    @Override
    public void close() {
        if(connection != null) {
            try {
                connection.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

  • 根据session对象创建dao接口的代理对象,它使用了代理模式,使用代理对象执行方法。

MapperProxy.java

public class MapperProxy implements InvocationHandler {
    //map的key是全限定类名+方法名
    private Map<String,Mapper> mappers;
    private Connection conn;
    public MapperProxy(Map<String,Mapper> mappers, Connection conn){
        this.mappers = mappers;
        this.conn = conn;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        String methodName = method.getName();
        //2.获取方法所在类的名称
        String className = method.getDeclaringClass().getName();
        //3.组合key
        String key = className+"."+methodName;
        //4.获取mappers中的Mapper对象
        Mapper mapper = mappers.get(key);
        //5.判断是否有mapper
        if(mapper == null){
            throw new IllegalArgumentException("传入的参数有误");
        }
        //6.调用工具类执行查询所有
        return new Executor().selectList(mapper,conn);
    }
}
  • 配置类:

Configuration.java

package com.itheima.mybatis.cfg;
public class Configuration {
    private String driver;
    private String url;
    private String username;
    private String password;
    private Map<String,Mapper> mappers = new HashMap<>();;
	...set()/get()...
}

Mapper.java

package com.itheima.mybatis.cfg;
public class Mapper {
    private String queryString;
    private String resultType;
	...set()/get()...
}

在这里插入图片描述

四、使用Mybatis实现CRUD

4.1 基于代理DAO

  • 搭建开发环境

    • 搭建入门案例中的开发环境
    • 修改dao接口
    public interface UserDao {
        public List<User> findAllUser();
        public void insertUesr(User user);
        public void updataUser(User user);
        public void deleteUser(Integer id);
        public User findById(Integer id);
        public List<User> findByName(String name);
    }
    
    • 修改测试类
    public class MybatisTest {
        private InputStream in;
        private SqlSession session;
        private UserDao userDao;
        @Before
        public void init(){
            try {
                in = Resources.getResourceAsStream("SqlMapConfig.xml");
            } catch (IOException e) {
                e.printStackTrace();
            }
            SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
            SqlSessionFactory build = builder.build(in);
            session = build.openSession();
            userDao = session.getMapper(UserDao.class);
        }
        @After
        public void destory(){
            session.commit();
            session.close();
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }    
    
    • 修改配置文件
    <?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.itheima.dao.UserDao">
         <!-- 查询全部 -->
        <select id="findAllUser" resultType="com.itheima.domain.User">
            SELECT * FROM USER ;
        </select>
         <!-- 插入操作 -->
        <insert id="insertUesr" parameterType="com.itheima.domain.User">
          INSERT INTO USER (username,birthday,sex,address) VALUES (#{username},#{birthday},#{sex},#{address}) where id=#{id};
        </insert>
         <!-- 更新操作 -->
        <update id="updataUser" parameterType="com.itheima.domain.User">
            UPDATE USER SET username=#{username},birthday=#{birthday},sex=#{sex},address=#{address};
        </update>
         <!-- 删除操作 -->
        <delete id="deleteUser" parameterType="Int">
            DELETE FROM user WHERE id=#{uid}
        </delete>
         <!-- 根据ID查询 -->
        <select id="findById" parameterType="Int" resultType="com.itheima.domain.User">
            SELECT * from USER WHERE id=#{id}
        </select>
         <!-- 模糊查询 -->
        <select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
            SELECT * from USER where username LIKE #{name }
        </select>
    </mapper>
    
  • 查询操作

    • 根据ID查询

      测试类中添加下列代码:

    @Test
    public void test05(){
        User userid = userDao.findById(49);
        System.out.println(userid);
    }
    
    • 查询全部

      测试类中添加下列代码:

    @Test
    public void test01() throws IOException {
        List<User> allUser = userDao.findAllUser();
        for (User user : allUser) {
            System.out.println(user);
        }
    }
    
    • 配置参数总结

    resultType 属性:于指定结果集的类型。

    parameterType 属性:用于指定传入参数的类型。

    sql 语句中使用#{}字符:它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。具体的数据是由#{}里面的内容决定的。

    #{}中内容的写法:由于数据类型是基本类型,所以此处可以随意写。

  • 更新操作

    • 测试类:
    @Test
    public void test03(){
        User user = new User();
        user.setUsername("张四");
        user.setBirthday(new Date(123346536));
        user.setAddress("山东省");
        user.setSex("女");
        userDao.updataUser(user);
    }
    
  • 保存操作

    • 测试类:
    @Test
    public void test02(){
        User user = new User();
        user.setUsername("张三");
        user.setBirthday(new Date(123346536));
        user.setAddress("山东省");
        user.setSex("男");
        userDao.insertUesr(user);
    }
    
    • 配置参数总结:

    parameterType 属性: 代表参数的类型,因为我们要传入的是一个类的对象,所以类型就写类的全名称。

    sql 语句中使用#{}字符: 它代表占位符,相当于原来 jdbc 部分所学的?,都是用于执行语句时替换实际的数据。 具体的数据是由#{}里面的内容决定的。

    #{}中内容的写法: 由于我们保存方法的参数是 一个 User 对象,此处要写 User 对象中的属性名称。 它用的是 ognl 表达式。

    ognl 表达式: 它是 apache 提供的一种表达式语言,全称是: Object Graphic Navigation Language 对象图导航语言 它是按照一定的语法格式来获取数据的。 语法格式就是使用 #{对象.对象}的方式 , #{user.username}它会先去找 user 对象,然后在 user 对象中找到 username 属性,并调用 getUsername()方法把值取出来。但是我们在 parameterType 属性上指定了实体类名称,所以可以省略 user. 而直接写 username。

  • 删除操作

    • 测试类
    @Test
    public void test04(){
        userDao.deleteUser(48);
    }
    
  • 模糊查询

    • 测试类
    @Test
    public void test06(){
        List<User> byName = userDao.findByName("%张%");
        for (User u : byName ) {
            System.out.println(u);
        }
    }
    
    • 配置文件总结

    #{}表示一个占位符号 通过#{}可以实现 preparedStatement 向占位符中设置值,自动进行 java 类型和 jdbc 类型转换, #{}可以有效防止 sql 注入。 #{}可以接收简单类型值或 pojo 属性值。 如果 parameterType 传输单个简单类 型值,#{}括号中可以是 value 或其它名称。

    表 示 拼 接 s q l 串 通 过 {}表示拼接 sql 串 通过 sql{}可以将 parameterType 传入的内容拼接在 sql中且不进行 jdbc 类型转换, 可 以 接 收 简 单 类 型 值 或 p o j o 属 性 值 , 如 果 p a r a m e t e r T y p e 传 输 单 个 简 单 类 型 值 , {}可以接收简 单类型值或 pojo 属性值,如果 parameterType 传输单个简单类型值, pojoparameterType{}括号中只能是 value

4.2 传统Dao开发

  • UserDao实现类
public class UserDaoImpl implements UserDao {
    private SqlSessionFactory factory;

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

    @Override
    public List<User> findAllUser() {
        SqlSession session = factory.openSession();
        List<User> users = session.selectList("com.itheima.dao.UserDao.findAllUser");
        session.close();
        return users;
    }

    @Override
    public void insertUesr(User user) {
        SqlSession session = factory.openSession();
        session.insert("com.itheima.dao.UserDao.insertUesr",user);
        session.commit();
        session.close();
    }

    @Override
    public void updataUser(User user) {
        SqlSession session = factory.openSession();
        session.update("com.itheima.dao.UserDao.updataUser",user);
        session.commit();
        session.close();
    }
    @Override
    public void deleteUser(Integer id) {
        SqlSession session = factory.openSession();
        session.insert("com.itheima.dao.UserDao.insertUesr",id);
        session.commit();
        session.close();
    }
}
  • 测试类
package com.itheima.test;

import com.itheima.dao.UserDao;
import com.itheima.dao.impl.UserDaoImpl;
import com.itheima.domain.User;
import org.apache.ibatis.io.Resources;
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.List;

public class MybatisTest {
    private InputStream in;
    private UserDao userDao;
    @Before
    public void init(){
        try {
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        userDao = new UserDaoImpl(builder.build(in));
    }
    @After
    public void destory(){
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Test
    public void test01() {
        List<User> allUser = userDao.findAllUser();
        for (User user : allUser) {
            System.out.println(user);
        }
    }
}

4.3 SqlMapConfig.xml配置文件

  • 配置内容和顺序:

-properties(属性)
–property -settings(全局配置参数)
–setting
-typeAliases(类型别名)
–typeAliase
–package -typeHandlers(类型处理器)
-objectFactory(对象工厂)
-plugins(插件)
-environments(环境集合属性对象)
–environment(环境子属性对象)
—transactionManager(事务管理)
—dataSource(数据源)
-mappers(映射器)
–mapper
–package

  • properties:此标签有两种配置方式

    • 第一种
    <properties>
        <property name="driver" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
        <property name="username" value="root"/>
        <property name="password" value="1234"/>
    </properties>
    
    • 第二种

      首先引入jdbc.properties配置文件

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/mybatis
    jdbc.username=root
    jdbc.password=1234
    

    ​ 然后设置properties

    <properties resource="jdbc.properties"/>
    
    • 数据源的引入方法
    <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </dataSource>
    
  • typeAliases

<typeAliases>
    <!--typeAlias用于配置别名。type属性指定的是实体类全限定类名。alias属性指定别名,当指定了别名就再区分大小写
        <typeAlias type="com.itheima.domain.User" alias="user"></typeAlias>-->

    <!-- 用于指定要配置别名的包,当指定之后,该包下的实体类都会注册别名,并且类名就是别名,不再区分大小写-->
    <package name="com.itheima.domain"></package>
</typeAliases>
  • mappers
<mappers>
    <!-- 注解开发方式 -->
    <mapper class="com.itheima.dao.UserDao"></mapper>
    <!-- xml开发方式 -->
    <mapper resource="com/itheima/dao/UserDao.xml"></mapper>
    <!-- 包扫描方式 -->
    <package name="com.itheima.dao"/>
</mappers>

五、事务与SQL动态语句

5.1 连接池技术

  • Mybatis连接池的分类

在这里插入图片描述

在Mybatis中可以将连接池分为一下三类

UNPOOLED:不使用连接池的数据源

POOLED:使用连接池的数据源

JNDI:使用JNDI实现的数据源

  • Mybatis数据源的配置

数据源的配置在SqlMapConfig.xml中的environment 的DataSource标签属性中进行配置:

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

5.2 事务控制

在mybatis中,为什么 CUD 过程中必须使用 sqlSession.commit()提交事务?主要原因就是它在连接池中取出的连接,都会将调用 connection.setAutoCommit(false)方法,这样我们 就必须使用 sqlSession.commit()方法,相当于使用了 JDBC 中的 connection.commit()方法实现事务提交。明白这一点后,我们现在一起尝试不进行手动提交,一样实现 CUD 操作。

public class MybatisTest {
    private InputStream in;
    private SqlSession session;
    private UserDao userDao;
    @Before
    public void init(){
        try {
            in = Resources.getResourceAsStream("SqlMapConfig.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        SqlSessionFactory build = builder.build(in);
        session = build.openSession(true);
        userDao = session.getMapper(UserDao.class);
    }
    @After
    public void destory(){
        session.commit();
        session.close();
        try {
            in.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    @Test
    public void test02(){
        User user = new User();
        user.setUsername("张三");
        user.setBirthday(new Date(123346536));
        user.setAddress("山东省德州市");
        user.setSex("男");
        userDao.insertUesr(user);
    }
}

5.3 动态SQL语句

  • 使用举例:
<?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.itheima.dao.UserDao">
    <update id="updataUser" parameterType="com.itheima.domain.QueryVo">
        UPDATE USER SET username=#{user.username},birthday=#{user.birthday},sex=#{user.sex},address=#{user.address}
        <where>
            <if test="ids != null and ids.size()>0">
                <foreach collection="ids" item="id" open="id in (" close=")" separator=",">
                    #{id}
                </foreach>
            </if>
        </where>
    </update>
    <select id="findByParamter" resultType="com.itheima.domain.User" parameterType="com.itheima.domain.User">
      SELECT * FROM USER
      <where>
          <if test="username != null">
              username LIKE  #{username }
          </if>
          <if test="sex != null">
              and sex=#{sex }
          </if>
      </where>
    </select>
</mapper>

六、多表查询

环境准备:根据下列sql语句创建数据库并创建实体类。

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','女','北京修正');
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);
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
  `ID` int(11) NOT NULL COMMENT '编号',
  `ROLE_NAME` varchar(30) default NULL COMMENT '角色名称',
  `ROLE_DESC` varchar(60) default NULL COMMENT '角色描述',
  PRIMARY KEY  (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `role`(`ID`,`ROLE_NAME`,`ROLE_DESC`) values (1,'院长','管理整个学院'),(2,'总裁','管理整个公司'),(3,'校长','管理整个学校');
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
  `UID` int(11) NOT NULL COMMENT '用户编号',
  `RID` int(11) NOT NULL COMMENT '角色编号',
  PRIMARY KEY  (`UID`,`RID`),
  KEY `FK_Reference_10` (`RID`),
  CONSTRAINT `FK_Reference_10` FOREIGN KEY (`RID`) REFERENCES `role` (`ID`),
  CONSTRAINT `FK_Reference_9` FOREIGN KEY (`UID`) REFERENCES `user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
insert  into `user_role`(`UID`,`RID`) values (41,1),(45,1),(41,2);

6.1 一对多

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">
 <mapper namespace="com.itheima.dao.UserDao">
    <resultMap id="userMap" type="com.itheima.domain.User">
        <id column="id" property="id"></id>
        <result column="username" property="username"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <result column="address" property="address"/>
        <!-- collection  部分定义了用户关联的账户信息。表示关联查询结果集 
			property="accounts" :关联查询的结果集存储在 User 对象的上哪个属性。 
			ofType="account" :指定关联查询的结果集中的对象类型即List中的对象类型。此处可以使用别名,也可以使用全限定名   -->
        <collection property="accounts" ofType="account">
            <id column="id" property="id"></id>
            <result column="uid" property="uid"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>
    <select id="findAllUser" resultMap="userMap">
        select u.*,a.id as aid ,a.uid,a.money from user u left outer join account a on u.id =a.uid
    </select>
    <select id="findById" parameterType="Int" resultType="com.itheima.domain.User">
        SELECT * from USER WHERE id=#{id}
    </select>
    <select id="findByName" parameterType="string" resultType="com.itheima.domain.User">
        SELECT * from USER where username LIKE #{name }
    </select>
</mapper>

6.2 多对多

account.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.itheima.dao.AccountDao">
    <resultMap id="accountMap" type="account">
        <id property="id" column="id"/>
        <result column="uid" property="uid"/>
        <result column="money" property="money"/>
        <!-- 它是用于指定从表方的引用实体属性的 -->
        <association property="user" javaType="user">
            <id property="id" column="id"/>
            <result property="username" column="username"/>
            <result property="birthday" column="birthday"/>
            <result property="sex" column="sex"/>
            <result property="address" column="address"/>
        </association>
    </resultMap>
    <select id="findAllAccount" resultMap="accountMap">
        SELECT u.*,a.id as aid,a.uid,a.money FROM user as u,account as a WHERE a.uid = u.id
    </select>
</mapper>

七、延迟加载

7.1 什么是延迟加载?

就是在需要用到数据时才进行加载,不需要用到数据时就不加载数据。延迟加载也称懒加载.

延迟加载的好处:先从单表查询,需要时再从关联表去关联查询,大大提高数据库性能,因为查询单表要比关联查询多张表速 度要快。

7.2 延迟加载的实现案例

  • 使用association
<?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.itheima.dao.IAccountDao">
    <!-- 定义封装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的内容
        select属性指定的内容:查询用户的唯一标识:
        column属性指定的内容:用户根据id查询时,所需要的参数的值
        -->
        <association property="user" column="uid" javaType="user" select="com.itheima.dao.IUserDao.findById"></association>
    </resultMap>
    <!-- 查询所有 -->
    <select id="findAll" resultMap="accountUserMap">
        select * from account
    </select>
    <!-- 根据用户id查询账户列表 -->
    <select id="findAccountByUid" resultType="account">
        select * from account where uid = #{uid}
    </select>
</mapper>
  • 使用collection
<?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.itheima.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="accounts" ofType="account" select="com.itheima.dao.IAccountDao.findAccountByUid" column="id"></collection>
    </resultMap>
    <!-- 查询所有 -->
    <select id="findAll" resultMap="userAccountMap">
        select * from user
    </select>
    <!-- 根据id查询用户 -->
    <select id="findById" parameterType="INT" resultType="user">
        select * from user where id = #{uid}
    </select>
</mapper>

7.3 缓存

  • 一级缓存:一级缓存是 SqlSession 级别的缓存,只要 SqlSession 没有 flush 或 close,它就存在。 每次执行CUD操作时会清空一级缓存

测试案例:

    /**
     * 测试一级缓存
     */
    @Test
    public void testFirstLevelCache(){
        User user1 = userDao.findById(41);
        System.out.println(user1);
//        sqlSession.close();
        //再次获取SqlSession对象
//        sqlSession = factory.openSession();
        sqlSession.clearCache();//此方法也可以清空缓存
  		userDao = sqlSession.getMapper(IUserDao.class);
        User user2 = userDao.findById(41);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }
 /**
     * 测试缓存的同步
     */
    @Test
    public void testClearlCache(){
        //1.根据id查询用户
        User user1 = userDao.findById(41);
        System.out.println(user1);
        //2.更新用户信息
        user1.setUsername("update user clear cache");
        user1.setAddress("北京市海淀区");
        userDao.updateUser(user1);
        //3.再次查询id为41的用户
        User user2 = userDao.findById(41);
        System.out.println(user2);
        System.out.println(user1 == user2);
    }
  • 二级缓存:二级缓存是 mapper 映射级别的缓存,多个 SqlSession 去操作同一个 Mapper 映射的 sql 语句,多个 SqlSession 可以共用二级缓存,二级缓存是跨 SqlSession 的。

    测试案例:

        @Test
        public void testFirstLevelCache(){
            SqlSession sqlSession1 = factory.openSession();
            IUserDao dao1 = sqlSession1.getMapper(IUserDao.class);
            User user1 = dao1.findById(41);
            System.out.println(user1);
            sqlSession1.close();//一级缓存消失
            SqlSession sqlSession2 = factory.openSession();
            IUserDao dao2 = sqlSession2.getMapper(IUserDao.class);
            User user2 = dao2.findById(41);
            System.out.println(user2);
            sqlSession2.close();
            System.out.println(user1 == user2);
        }
    

八、注解开发

8.1 常用注解

@Insert:实现新增
@Update:实现更新
@Delete:实现删除
@Select:实现查询
@Result:实现结果集封装
@Results:可以与
@Result 一起使用,封装多个结果集
@ResultMap:实现引用
@Results 定义的封装
@One:实现一对一结果集封装
@Many:实现一对多结果集封装
@SelectProvider: 实现动态 SQL 映射
@CacheNamespace:实现注解二级缓存的使用

8.2 实现案例

  • 创建项目(略)

  • 引入约束(略)

  • 创建数据库以及实现类(略)

  • 创建dao

    • AccountDao
    public interface AccountDao {
        /**
         * 查询所有账户,并且获取每个账户所属的用户信息
         * @return
         */
        @Select("select * from account")
        @Results(id="accountMap",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.itheima.dao.IUserDao.findById",fetchType= FetchType.EAGER))
        })
        List<Account> findAll();
    
        /**
         * 根据用户id查询账户信息
         * @param userId
         * @return
         */
        @Select("select * from account where uid = #{userId}")
        List<Account> findAccountByUid(Integer userId);
    }
    
    • UserDao
    @CacheNamespace(blocking = true)
    public interface IUserDao {
        /**
         * 查询所有用户
         * @return
         */
        @Select("select * from user")
        @Results(id="userMap",value={
                @Result(id=true,column = "id",property = "userId"),
                @Result(column = "username",property = "userName"),
                @Result(column = "address",property = "userAddress"),
                @Result(column = "sex",property = "userSex"),
                @Result(column = "birthday",property = "userBirthday"),
                @Result(property = "accounts",column = "id",
                        many = @Many(select = "com.itheima.dao.IAccountDao.findAccountByUid",
                                    fetchType = FetchType.LAZY))
        })
        List<User> findAll();
        /**
         * 根据id查询用户
         * @param userId
         * @return
         */
        @Select("select * from user  where id=#{id} ")
        @ResultMap("userMap")
        User findById(Integer userId);
    
        /**
         * 根据用户名称模糊查询
         * @param username
         * @return
         */
        @Select("select * from user where username like #{username} ")
        @ResultMap("userMap")
        List<User> findUserByName(String username);
    }
    
  • 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>
    <!--配置开启二级缓存-->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

    <!--配置别名-->
    <typeAliases>
        <package name="com.itheima.domain"></package>
    </typeAliases>
    <!-- 配置环境-->
    <environments default="mysql">
        <environment id="mysql">
            <transactionManager type="JDBC"></transactionManager>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"></property>
                <property name="url" value="${jdbc.url}"></property>
                <property name="username" value="${jdbc.username}"></property>
                <property name="password" value="${jdbc.password}"></property>
            </dataSource>
        </environment>
    </environments>
    <!-- 指定带有注解的dao接口所在位置 -->
    <mappers>
       <package name="com.itheima.dao"></package>
    </mappers>
</configuration>

九、总结

以上内容即为对Mybatis的全部总结,如有错误,欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值