> 文档中心 > Mybatis框架学习

Mybatis框架学习


前言
  🎄:CSDN的小伙伴们大家好,今天跟大家分享一个我们后台开发使用的框架——Mybatis。如果这篇文章对你有用,麻烦给我点个小赞以示鼓励吧🎄
  🏡:博客主页:空山新雨后的java知识图书馆
  ☀️:天气晴朗。
  📝:成大功者,不顾小嫌;建远略者,不期近效。——陈宏谋📝
  📖上一篇文章:旅游网站后台信息管理——简单版(增删改查)📖
  👏欢迎大家一起学习,进步。加油👊
Mybatis框架学习


文章目录

  • 一、何为mybatis,为什么要学习mybatis?
  • 二、mybatis的简单体验
    • 2.1、引入mybatis的坐标
    • 2.2、创建测试用的user数据库表
    • 2.3、创建测试用的user实体类
    • 2.4、编写映射文件UserMapper.xml
    • 2.5、核心配置文件SQLMapConfig的编写
    • 2.6、编写测试类
  • 三、mybatis的映射文件的参数简介
    • 3.1、映射文件的DTD约束头:
    • 3.2、根标签
    • 3.3、子标签
    • 3.4、动态SQL语句
      •   3.4.1、动态 SQL语句概述
      •   3.4.2、动态SQL之 ``
      •   3.4.3、动态SQL之 ``
    • 3.5、SQL片段抽取
  • 四、mybatis的核心配置文件参数简介
    • 4.1、mybatis的核心配置文件的层级关系
    • 4.2mybatis的核心配置文件的常用配置解析
      •   4.2.1、environment 标签
      •   4.2.2、mapper标签
      •   4.2.3、properties标签
      •   4.2.4、typeAliases标签
    • 4.3、typeHandler标签
    • 4.4、plugins标签,演示插入分页助手插件
  • 五、mybatis相关的API
    • 5.1、SQLsession工厂构建器,SQLSessionFactoryBuilder
    • 5.2、SqlSession工厂对象SqlSessionFactory
    • 5.3、SQLSession会话对象
  • 六、mybatis的增删改查操作
    • 6.1、mybatis的插入数据的操作
      •   6.1.1、映射文件的编写:
      •   6.1.2、测试:
      •   6.1.3、插入操作的注意事项:
    • 6.2、mybatis的修改数据操作
      •   6.2.1、编写userMapper映射文件
      •   6.2.2、测试
      •   6.2.3、修改操作时注意的问题
    • 6.3、mybatis的删除数据的操作
      •   6.3.1、编写userMapper映射文件
      •   6.3.2、测试
      •   6.3.3、删除操作注意事项
  • 七、mybatis的Dao实现
    • 7.1、mybatisDao实现简介
    • 7.2、Mapper 接口开发需要遵循以下规范:
    • 7.3、演示
  • 八、mybatis的多表查询
    • 8.1、一对一查询测试模型
    • 8.2、一对多查询模型
    • 8.3、多对多的查询模型
    • 8.4、总结
  • 九、mybatis的注解开发
    • 9.1、注解开发简介
    • 9.2、注解开发核心配置文件的配置
    • 9.3、mybatis的注解实现复杂映射开发
      •   9.3.1、一对一查询模型
      •   9.3.2、一对多模型查询
      •   9.3.3、多对多查询模型

一、何为mybatis,为什么要学习mybatis?

mybatis的百度百科定义:
  MyBatis 是一款优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。
  那么通过学习mybatis可以更简单的完成传统开发中Dao层的操作,大大提高了开发者的开发效率,使我们的注意力主要集中在SQL语句上面即可。

二、mybatis的简单体验

  要想使用mybatis,首先你得下载mybatis的jar包。下载地址:mybatis——http://www.mybatis.org/mybatis-3/

  maven项目中引用mybatis的坐标即可。

2.1、引入mybatis的坐标

    <dependencies> <dependency>     <groupId>mysql</groupId>     <artifactId>mysql-connector-java</artifactId>     <version>5.1.32</version> </dependency> <dependency>     <groupId>org.mybatis</groupId>     <artifactId>mybatis</artifactId>     <version>3.4.6</version> </dependency> <dependency>     <groupId>junit</groupId>     <artifactId>junit</artifactId>     <version>4.13.2 </version>     <scope>test</scope> </dependency> <dependency>     <groupId>log4j</groupId>     <artifactId>log4j</artifactId>     <version>1.2.12</version> </dependency>    </dependencies>

2.2、创建测试用的user数据库表

在这里插入图片描述

2.3、创建测试用的user实体类

package com.study.domain;/** * @author wang * @version 1.0 * @packageName com.study.domain * @className User * @date 2022/4/18 10:11 * @Description User实体类 */public class User {    private int id;    private String username;    private String password;

  注意提供set,get方法,篇幅限制,这里就不演示set,get方法了。

2.4、编写映射文件UserMapper.xml

文件名字随你的喜好取就行。

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="userMapper">        <delete id="delete" parameterType="int"> delete from user_u where id=#{id}    </delete>        <update id="update" parameterType="com.study.domain.User"> update user_u set username=#{username},password=#{password} where id=#{id};    </update>        <insert id="saveUser" parameterType="com.study.domain.User"> insert into user_u(username,password) values(#{username},#{password});    </insert>        <select id="findAll" resultType="user"> select * from user_u    </select>    <select id="findOne" resultType="user" parameterType="int"> select * from user_u where id=#{id}    </select></mapper>

2.5、核心配置文件SQLMapConfig的编写

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>        <properties resource="jdbc.properties"></properties>        <typeAliases> <typeAlias type="com.study.domain.User" alias="user"></typeAlias>    </typeAliases>        <environments default="development">  <environment id="development">          <transactionManager type="JDBC"></transactionManager>          <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> </environment>    </environments>        <mappers> <mapper resource="com\study\mapper\UserMapper.xml"></mapper>    </mappers></configuration>

jdbc.properties文件

jdbc.driver=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/testjdbc.username=rootjdbc.password=root

2.6、编写测试类

这里的测试只演示一个,我演示的查询。

    /**     * @Date 2022/4/18 10:50     * @Param     * @Return void     * @MetodName test1     * @Author wang     * @Description 该方法测试第一个SQL语句,用mybatis框架实现的     */    @Test    public void test1() throws IOException { //获得核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapManager.xml"); //获取SQLsession工厂对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获得session会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //执行操作,参数是配置文件中namespace.id的去获得唯一的SQL语句 List<User> users = sqlSession.selectList("userMapper.findAll"); System.out.println(users); //释放资源 sqlSession.close();    }

  这里的UserMapper.findAll指向的就是配置文件中的id为findAll的那条SQL语句。
  另外这里只演示测试,如果要是增删改,必须手动提交事务,才能生效。
有两种做法提交事务
第一种SqlSession sqlSession = sqlSessionFactory.openSession(true);将openSession传入一个参数,true,就可以自动提交事务了。
第二种,就是自己手动提交了。sqlSession.commit();

  测试结果:

User{id=1, username='张三', password='123456'}User{id=2, username='lisi', password='123465'}User{id=4, username='周瑜', password='45454545'}

在这里插入图片描述

三、mybatis的映射文件的参数简介

3.1、映射文件的DTD约束头:

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">映射文件的DTD约束头

3.2、根标签

<mapper namespace="userMapper">

  根标签,其中namespace为命名空间,与子标签中的id一起组成查询的标识

3.3、子标签

    <select id="findAll" resultType="com.study.domain.User">

  子标签,执行的操作,insert,update等,resultType为查询结果对应的实体类型

3.4、动态SQL语句

  3.4.1、动态 SQL语句概述

  Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了.

  3.4.2、动态SQL之

  我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。这种情况在我们的多条件组合查询中经常会碰到。
配置文件代码

<mapper namespace="com.study.Dao.UserDao"><select id="findByCondition" parameterType="user" resultType="user">   <!-- -->  <!-- --> <!-- -->  <!-- --> <!-- -->  <!--   上述语法仍旧存在小问题,因此改进版,sql拼接需要依赖where1=1,而mybatis存在一个where标签共我们使用 --> select * from user_u <where>     <if test="id != 0">  and id=#{id}     </if>     <if test="username != null">  and username=#{username}     </if>     <if test="password != null">  and password=#{password}     </if> </where>    </select></mapper>

  上述代码会自动根据条件,将后续的SQL进行拼接。
测试代码部分

//获取代理实现 UserDao mapper = sqlSession.getMapper(UserDao.class); //模拟条件user User user = new User(); user.setId(1);// user.setUsername("张三");// user.setPassword("123456"); //执行方法// User byCondition = mapper.findByCondition(user);// System.out.println(byCondition);//User{id=1, username='张三', password='123456'}

  3.4.3、动态SQL之

  循环执行sql的拼接操作,例如:SELECT * FROM USER WHERE id IN (1,2,5)。
配置文件代码

    <select id="findByIds" parameterType="list" resultType="user" >/*      这里原始的查询语句,无法达到动态的使用效果,因此使用foreach进行改进 select * from user_u where id in(1,2,3);*/ select * from user_u <where>/* 语句中Collection对应的是传进来的参数,我们这里传进来的是一个list集合,因此,写list,     open对应的是语句以什么开始拼接,close对应的是语句以什么结束拼接,separator是分隔符,也就是参数之间的分隔符,为,     item就是每一个参数变量,我们用的item*/     <foreach collection="list" open="id in(" close=")" separator="," item="id">  /*这里就只需要对参数进行接收就可以对集合中的每个参数进行拼接。*/  #{id}     </foreach> </where>    </select>

测试代码部分

 List<Integer> ids = new ArrayList<Integer>(); ids.add(1); ids.add(2); List<User> userList = mapper.findByIds(ids); System.out.println(userList); //[User{id=1, username='张三', password='123456'}, User{id=2, username='lisi', password='123465'}]

foreach标签的属性含义
标签用于遍历集合,它的属性:

•collection:代表要遍历的集合元素,注意编写时不要写#{}•open:代表语句的开始部分•close:代表结束部分•item:代表遍历集合的每个元素,生成的变量名•sperator:代表分隔符

3.5、SQL片段抽取

  SQL中可将重复的SQL提取出来,使用时用include引用即可,最终达到SQL重用的目的
代码演示

    <sql id="selectUser">select * from user_u</sql>    <select id="findByCondition" parameterType="user" resultType="user">   <!-- -->  <!-- --> <!-- -->  <!-- --> <!-- -->  <!--   上述语法仍旧存在小问题,因此改进版,sql拼接需要依赖where1=1,而mybatis存在一个where标签共我们使用 --> /*引用抽取的SQL语句*/ <include refid="selectUser"></include> <where>     <if test="id != 0">  and id=#{id}     </if>     <if test="username != null">  and username=#{username}     </if>     <if test="password != null">  and password=#{password}     </if> </where>    </select>
语法上需要用到<SQL>标签和<include>标签<sql>标签进行抽取<include>标签进行引用

在这里插入图片描述

四、mybatis的核心配置文件参数简介

4.1、mybatis的核心配置文件的层级关系

configuration 配置
  properties 属性
  settings 设置
  typeAliases 类型别名
  typeHandlers 类型处理器
  objectFactory 对象工厂
  plugins 插件
  environments 环境
    environment 环境变量
      transactionManager 事务管理器
      DataSource 数据源
  dataBaseldProvider 数据库厂商标识
  mappers 映射器

4.2mybatis的核心配置文件的常用配置解析

  4.2.1、environment 标签

  其中,事务管理器(transactionManager)类型有两种:

   •JDBC:这个配置就是直接使用了JDBC 的提交和回滚设置,它依赖于从数据源得到的连接来管理事务作用域。
  •MANAGED:这个配置几乎没做什么。它从来不提交或回滚一个连接,而是让容器来管理事务的整个生命周期(比如 JEE应用服务器的上下文)。 默认情况下它会关闭连接,然而一些容器并不希望这样,因此需要将 closeConnection 属性设置为 false来阻止它默认的关闭行为。

  其中,数据源(dataSource)类型有三种:

UNPOOLED:这个数据源的实现只是每次被请求时打开和关闭连接。
POOLED:这种数据源的实现利用“池”的概念将 JDBC连接对象组织起来。
JNDI:这个数据源的实现是为了能在如 EJB 或应用服务器这类容器中使用,容器可以集中或在外部配置数据源,然后放置一个 JNDI 上下文的引用。

  4.2.2、mapper标签

该标签的作用是加载映射的,加载方式有如下几种

•使用相对于类路径的资源引用:

•使用完全限定资源定位符(URL),例如:

•使用映射器接口实现类的完全限定类名,例如:

•将包内的映射器接口实现全部注册为映射器,例如:

  4.2.3、properties标签

实际开发中,习惯将数据源的配置信息单独抽取成一个properties文件,该标签可以加载额外配置的properties文件
子主题 1

  4.2.4、typeAliases标签

类型别名是为Java 类型设置一个短的名字。原来的类型名称配置如下
Mybatis框架学习
配置typeAliases,为com.itheima.domain.User定义别名为user
Mybatis框架学习
注意
  配置的typeAliases标签必须在properties的标签后面,否则会报错
  上面我们是自定义的别名,mybatis框架已经为我们设置好的一些常用的类型的别名
子主题 1

4.3、typeHandler标签

  无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。下表描述了一些默认的类型处理器(截取部分)。
在这里插入图片描述
  你可以重写类型处理器或创建你自己的类型处理器来处理不支持的或非标准的类型。具体做法为:
  实现 org.apache.ibatis.type.TypeHandler 接口, 或继承一个很便利的org.apache.ibatis.type.BaseTypeHandler,
  然后可以选择性地将它映射到一个JDBC类型。
  例如需求:一个Java中的Date数据类型,我想将之存到数据库的时候存成一个1970年至今的毫秒数,取出来时转换成java的Date,即java的Date与数据库的varchar毫秒值之间转换。
开发步骤

①定义转换类继承类BaseTypeHandler②覆盖4个未实现的方法,其中setNonNullParameter为java程序设置数据到数据库的回调方法,getNullableResult为查询时 mysql的字符串类型转换成 java的Type类型的方法③在MyBatis核心配置文件中进行注册④测试转换是否正确

handler代码演示

package com.study.handler;import org.apache.ibatis.type.BaseTypeHandler;import org.apache.ibatis.type.JdbcType;import java.sql.CallableStatement;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.Date;/** * @author wang * @version 1.0 * @packageName com.study.handler * @className DateTypeHandler * @date 2022/4/19 16:15 * @Description 自定义类型转换处理器 */public class DateTypeHandler extends BaseTypeHandler<Date> {    @Override    /**     * 将date类型转换为毫秒值     */    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Date date, JdbcType jdbcType) throws SQLException { long time = date.getTime(); preparedStatement.setLong(i,time);    }    /**     * 将毫秒值转换为date     * @param resultSet     * @param s     * @return     * @throws SQLException     */    @Override    public Date getNullableResult(ResultSet resultSet, String s) throws SQLException { long aLong = resultSet.getLong(s); Date date = new Date(aLong); return date;    }    @Override    public Date getNullableResult(ResultSet resultSet, int i) throws SQLException { long aLong = resultSet.getLong(i); Date date = new Date(aLong); return date;    }    @Override    public Date getNullableResult(CallableStatement callableStatement, int i) throws SQLException { long aLong = callableStatement.getLong(i); Date date = new Date(aLong); return date;    }}

核心配置文件演示

    <typeHandlers> <typeHandler handler="com.study.handler.DateTypeHandler"></typeHandler>    </typeHandlers>

4.4、plugins标签,演示插入分页助手插件

  MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据
开发步骤
①导入通用PageHelper的坐标

<dependency>    <groupId>com.github.pagehelper</groupId>    <artifactId>pagehelper</artifactId>    <version>3.7.5</version></dependency><dependency>    <groupId>com.github.jsqlparser</groupId>    <artifactId>jsqlparser</artifactId>    <version>0.9.1</version></dependency>

②在mybatis核心配置文件中配置PageHelper插件

<plugin interceptor="com.github.pagehelper.PageHelper">        <property name="dialect" value="mysql"/></plugin>

③测试分页数据获取

  PageHelper.startPage(2, 3); //User{id=5, username='周瑜', password='45454545', date=Tue Apr 19 17:07:50 CST 2022} //User{id=6, username='周瑜', password='45454545', date=Tue Apr 19 17:08:00 CST 2022} //User{id=7, username='周瑜', password='45454545', date=Tue Apr 19 17:08:04 CST 2022} List<User> userList = mapper.findAll(); for (User user : userList) {     System.out.println(user); } //这是通过分页助手的其他参数来完成的 PageInfo<User> pageInfo = new PageInfo<User>(userList); System.out.println("当前页码:" + pageInfo.getPageNum()); System.out.println("上一页:" + pageInfo.getPrePage()); System.out.println("下一页:" + pageInfo.getNextPage()); System.out.println("是否是第一页:" + pageInfo.isIsFirstPage()); System.out.println("是否是最后一页:" + pageInfo.isIsLastPage()); System.out.println("当前显示条目数:" + pageInfo.getPageSize()); System.out.println("总条目数;" + pageInfo.getTotal()); System.out.println("总页数:" + pageInfo.getPages()); System.out.println("数据库查询的开始条目:第" + pageInfo.getStartRow() + "条"); /* * 当前页码:2上一页:1下一页:3是否是第一页:false是否是最后一页:false当前显示条目数:3总条目数;10总页数:4数据库查询的开始条目:第4条*/

在这里插入图片描述

五、mybatis相关的API

5.1、SQLsession工厂构建器,SQLSessionFactoryBuilder

  通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象
代码演示

String resource = "org/mybatis/builder/mybatis-config.xml"; InputStream inputStream = Resources.getResourceAsStream(resource); SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(inputStream);

  其中, Resources 工具类,这个类在 org.apache.ibatis.io 包中。Resources 类帮助你从类路径下、文件系统或一个 web URL 中加载资源文件。
  导包:import org.apache.ibatis.io.Resources;

5.2、SqlSession工厂对象SqlSessionFactory

  SqlSessionFactory 有多个个方法创建SqlSession 实例。常用的有如下两个:

方法 解释
openSession() 会默认开启一个事务,但事务不会自动提交,也就意味着需要手动提交该事务,更新操作数据才会持久化到数据库中
openSession(boolean autoCommit) 参数为是否自动提交,如果设置为true,那么不需要手动提交事务

5.3、SQLSession会话对象

  SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法。
执行语句的方法主要有

T selectOne(String statement, Object parameter) :查找一个对象
ListselectList(String statement, Object parameter) :查找一个集合的对象
int insert(String statement, Object parameter) :插入数据
int update(String statement, Object parameter) :更新数据
int delete(String statement, Object parameter):删除数据

操作事务的方法主要有

void commit() :提交事务
void rollback() :回滚

在这里插入图片描述

六、mybatis的增删改查操作

6.1、mybatis的插入数据的操作

  6.1.1、映射文件的编写:

    <insert id="saveUser" parameterType="com.study.domain.User"> insert into user_u(username,password) values(#{username},#{password});    </insert>

  6.1.2、测试:

    /**     * 测试插入语句     */    @Test    public void test2() throws IOException { //模拟插入对象的值 User user = new User(); user.setUsername("park"); user.setPassword("123"); //加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapManager.xml"); //获取SQLsession工厂的对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取session会话对象 SqlSession sqlSession = sqlSessionFactory.openSession(); sqlSession.insert("userMapper.saveUser", user); //提交事务,如果增删改操作不提交事务,是无法对数据库表进行修改操作的。 sqlSession.commit(); //释放资源 sqlSession.close();    }

  6.1.3、插入操作的注意事项:

•插入语句使用insert标签•在映射文件中使用parameterType属性指定要插入的数据类型(指定全包名)•Sql语句中使用#{实体属性名}方式引用实体中的属性值•插入操作使用的API是sqlSession.insert(“命名空间.id”,实体对象);•插入操作涉及数据库数据变化,所以要使用sqlSession对象显示的提交事务,即sqlSession.commit() 

6.2、mybatis的修改数据操作

  6.2.1、编写userMapper映射文件

代码演示

<update id="update" parameterType="com.study.domain.User">    update user_u set username=#{username},password=#{password} where id=#{id};</update>

  6.2.2、测试

/**     * 测试修改操作     */    @Test    public void update() throws IOException { //模拟修改的对象 User user = new User(); user.setId(3); user.setUsername("lucy"); user.setPassword("555"); //获取核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapManager.xml"); //获取SQLsession的工厂对象 SqlSessionFactory sqlsessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取session会话对象 SqlSession sqlSession = sqlsessionFactory.openSession(); //执行SQL sqlSession.update("userMapper.update",user); //提交事务 sqlSession.commit(); //关闭资源 sqlSession.close();    }

  6.2.3、修改操作时注意的问题

•修改语句使用update标签•修改操作时使用的API是sqlSession.update(“命名空间.id”,实体对象);

6.3、mybatis的删除数据的操作

  6.3.1、编写userMapper映射文件

    <delete id="delete" parameterType="java.lang.Integer"> delete from user_u where id=#{id}    </delete>

  6.3.2、测试

/**     * 测试删除操作     */    @Test    public void delete() throws IOException { //获取核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapManager.xml"); //获取SQLsession工厂对象 SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取session会话对象 SqlSession sqlSession = build.openSession(); //执行sql sqlSession.delete("userMapper.delete",3); //提交事务 sqlSession.commit(); //关闭资源 sqlSession.close();    }

  6.3.3、删除操作注意事项

• 删除语句使用delete标签•Sql语句中使用#{任意字符串}方式引用传递的单个参数•删除操作使用的API是sqlSession.delete(“命名空间.id”,Object);

在这里插入图片描述

七、mybatis的Dao实现

7.1、mybatisDao实现简介

  以前我们写dao层的实现,就是dao层写一个实现类,并实现其中的方法,达到目的。
  今天我们使用mybatis提供的代理开发方式实现 DAO 层的开发,这种方式是我们后面进入企业的主流。
  Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同Dao接口实现类方法。

7.2、Mapper 接口开发需要遵循以下规范:

1) Mapper.xml文件中的namespace与mapper接口的全限定名相同2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

7.3、演示

mapper接口:

public interface UserMapper {    public List<User> findAll();    public User findById(int id);}

mapper配置文件代码演示

<mapper namespace="com.study.Dao.UserMapper">    <select id="findAll" resultType="user">    select * from user_u</select>    <select id="findById" resultType="user" parameterType="int"> select * from user_u where id=#{id}    </select></mapper>

测试代码:

public static void main(String[] args) throws IOException { //获取核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapManager.xml"); //获取SQLsessionfactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取SQLsession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //获取代理实现 UserMapper mapper = sqlSession.getMapper(UserMapper.class); //执行方法 List<User> all = mapper.findAll(); System.out.println(all);//[User{id=1, username='张三', password='123456'}, User{id=2, username='lisi', password='123465'}] User user = mapper.findById(1); System.out.println(user);//User{id=1, username='张三', password='123456'}    }

在这里插入图片描述
注意:这里的resultType写的user,是因为我在核心配置文件中给这个实体类取的别名叫user。

<typeAliases> <typeAlias type="com.study.domain.User" alias="user"></typeAlias></typeAliases>

在这里插入图片描述

八、mybatis的多表查询

8.1、一对一查询测试模型

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
  一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

order表

    private int id;    private Date orderTime;    private double total;    //该订单的所属用户    private User user;

数据库对应着创建即可

重点就是userMapper中的封装

<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.study.mapper.OrderMapper">            <resultMap id="selectAll" type="order">   <id column="oid" property="id"></id> <result column="ordertime" property="orderTime"></result> <result column="total" property="total"></result> <!-- --> <!-- --> <!-- --> <!-- -->  <association property="user" javaType="user">     <id column="uid" property="id"></id>     <result column="username" property="username"></result>     <result column="password" property="password"></result>     <result column="birthday" property="birthday"></result> </association>    </resultMap>    <select id="findAll" resultMap="selectAll"> SELECT *,o.`id` oid FROM user_u u,`order` o WHERE o.`uid`=u.`id`;    </select></mapper>

测试代码:

 @Test    /**     * 测试查蕈order订单信息     */    public void testSelect() throws IOException { //加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //获取SQLSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取SQLSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); OrderMapper mapper = sqlSession.getMapper(OrderMapper.class); List<Order> orderList = mapper.findAll(); for (Order order : orderList) {     System.out.println(order); } sqlSession.close(); /*Order{id=6, orderTime=Thu Jan 01 08:00:02 CST 1970, total=0.0, user=User{id=1, username='张三', password='123456', birthday=null, orderList=null}}Order{id=7, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4545.0, user=User{id=2, username='lisi', password='123465', birthday=null, orderList=null}}Order{id=8, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4222.0, user=User{id=1, username='张三', password='123456', birthday=null, orderList=null}}Order{id=9, orderTime=Thu Jan 01 08:00:02 CST 1970, total=1111.0, user=User{id=1, username='张三', password='123456', birthday=null, orderList=null}}Order{id=10, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4545.0, user=User{id=1, username='张三', password='123456', birthday=null, orderList=null}}*/    }

8.2、一对多查询模型

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
  一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

User实体

public class User {    private int id;    private String username;    private String password;    private Date birthday;    //用于存储对应的order    private List<Order> orderList;

UserMapper接口:

public interface UserMapper {    public List<User> findAll();}

UserMapper的配置

<mapper namespace="com.study.mapper.UserMapper">        <resultMap id="selectAll" type="user"> <id column="uid" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> <result column="birthday" property="birthday"></result>  <collection property="orderList" ofType="order">     <id column="oid" property="id"></id>     <result column="ordertime" property="orderTime"></result>     <result column="total" property="total"></result> </collection>    </resultMap>    <select id="findAll" resultMap="selectAll"> select * ,o.id oid from user_u u,`order` o where o.uid=u.id    </select></mapper>

测试结果

    /**     *测试一对多的关系     */    @Test    public void testSe() throws IOException { //加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //获取SQLSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取SQLSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //获取代理实现 UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> all = mapper.findAll(); for (User user : all) {     System.out.println(user); } sqlSession.close();/*User{id=1, username='张三', password='123456', birthday=null, orderList=[Order{id=6, orderTime=Thu Jan 01 08:00:02 CST 1970, total=0.0, user=null}, Order{id=8, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4222.0, user=null}, Order{id=9, orderTime=Thu Jan 01 08:00:02 CST 1970, total=1111.0, user=null}, Order{id=10, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4545.0, user=null}]}User{id=2, username='lisi', password='123465', birthday=null, orderList=[Order{id=7, orderTime=Thu Jan 01 08:00:02 CST 1970, total=4545.0, user=null}]}*/    }

8.3、多对多的查询模型

用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用

多对多查询的需求:查询用户同时查询出该用户的所有角色

Role实体

public class Role {    private int id;    private String roleName;    private String roleDesc;

注意提供set,get方法

UserMapper

public List<User> findRole();

配置UserMapper.xml

     <resultMap id="RoleMap" type="user">  <id column="userId" property="id"></id> <result column="username" property="username"></result> <result column="password" property="password"></result> <result column="birthday" property="birthday"></result>  <collection property="roleList" ofType="role">     <id column="roleId" property="id"></id>     <result column="roleName" property="roleName"></result>     <result column="roleDesc" property="roleDesc"></result> </collection>    </resultMap>    <select id="findRole" resultMap="RoleMap"> select * from user_u u ,user_role ur,role r where u.id=ur.userId and r.id = ur.roleId    </select>

测试结果:

/**     * 测试多对多     */    @Test    public void testRole() throws IOException { //加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //获取SQLSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取SQLSession的对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //获取代理实现 UserMapper mapper = sqlSession.getMapper(UserMapper.class); List<User> all = mapper.findRole(); for (User user : all) {     System.out.println(user); } sqlSession.close(); /*User{id=1, username='张三', password='123456', birthday=null, orderList=null, roleList=[Role{id=1, roleName='院长', roleDesc='管理学院'}, Role{id=3, roleName='教授 ', roleDesc='讲授知识'}]}User{id=2, username='lisi', password='123465', birthday=null, orderList=null, roleList=[Role{id=2, roleName='副院长', roleDesc='辅助管理学院'}]}User{id=4, username='周瑜', password='45454545', birthday=Tue Apr 19 16:21:43 CST 2022, orderList=null, roleList=[Role{id=3, roleName='教授 ', roleDesc='讲授知识'}]}*/    }

8.4、总结

mybatis多表配置方式

一对一配置:使用做配置一对多配置:使用+做配置多对多配置:使用+做配置

在这里插入图片描述

九、mybatis的注解开发

9.1、注解开发简介

  这几年来注解开发越来越流行,Mybatis也可以使用注解开发方式,这样我们就可以减少编写Mapper映射文件了。
mybatis常用注解

@Insert:实现新增@Update:实现更新@Delete:实现删除@Select:实现查询@Result:实现结果集封装@Results:可以与@Result 一起使用,封装多个结果集@One:实现一对一结果集封装@Many:实现一对多结果集封装

9.2、注解开发核心配置文件的配置

  之前我们是通过加载映射文件来进行开发,那么使用注解我们就不需要加载映射文件了,那么有两种方式可以用来开发
两种方式修改加载核心配置文件

 <mappers>        <mapper class="com.itheima.mapper.UserMapper"></mapper></mappers><mappers>        <package name="com.itheima.mapper"></package></mappers>

9.3、mybatis的注解实现复杂映射开发

  实现复杂关系映射之前我们可以在映射文件中通过配置来实现,使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置

注解 说明
@Results 代替的标签是 该注解中可以使用单个@Result注解,也可以使用@Result集合,使用格式:@Result({@Result(),@Result()})或@Results(@Result())
@Result 代替了标签和标签 @Result中属性介绍:column:数据库的列名;property:需要装配的属性名;one:需要使用@one注解(@Result(one=@one)());many:需要使用many注解(@Result(mang=@many)())
@one(一对一) 代替了标签,是多表查询的关键,在注解中用来指定子查询返回单一对象;@one注解属性介绍:select:指定用来多表查询的sqlMapper;使用格式:@Result(column=“”,property=“”,one=@One(select=“”)
@many(多对一) 代替了标签,是多表查询的关键,在注解中使用指定子查询返回对象的集合。使用格式:@Result(property=“”,column=“”,mang=@many(select=“”))

  9.3.1、一对一查询模型

模型:
  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
  一对一查询的需求:查询一个订单,与此同时查询出该订单所属的用户

User和Order的实体类

public class Order {    private int id;    private Date ordertime;    private double total;    //代表当前订单从属于哪一个客户    private User user;}public class User { private int id;    private String username;    private String password;    private Date birthday;}

OrderMapper接口

public interface OrderMapper {    List<Order> findAll();}

使用注解配置:

方式一:

@Select("select *,o.id oid from `order` o,user_u u where u.id=o.uid")    @Results({     @Result(column = "oid" ,property = "id"),     @Result(column = "ordertime" ,property = "orderTime"),     @Result(column = "total" ,property = "total"),     @Result(column = "uid" ,property = "user.id"),     @Result(column = "username" ,property = "user.username"),     @Result(column = "password" ,property = "user.password")    })    public List<Order> findAll();

方式二:

    @Select("select *from `order`")    @Results({     @Result(column = "oid", property = "id"),     @Result(column = "ordertime", property = "orderTime"),     @Result(column = "total", property = "total"),     @Result(      //在查询出来的结果中要封装的order中的属性名称,      property = "user",      column = "uid",//另外一个查询需要的参数,根据表中UID的字段,就是user中的id      javaType = User.class,//要封装的实体类型      one = @One(select = "com.study.mapper.UserMapper.findUserById")//一对一的进行封装,调用userMapper中的findUserById的方法,查询处      //查询出被封装好的user对象到该order对象的user属性中     )    })    public List<Order> findAll();

测试结果:

    private OrderMapper mapper;    @Before    public void before() throws IOException { //加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //获取SQLSessionFactory对象 SqlSessionFactory build = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取SQLSession对象 SqlSession sqlSession = build.openSession();  mapper = sqlSession.getMapper(OrderMapper.class);    }    @Test    public void findAll() { List<Order> all = mapper.findAll(); for (Order order : all) {     System.out.println(order); } /*Order{id=6, orderTime=Wed Apr 20 00:00:00 CST 2022, total=0.0, user=User{id=1, username='张三', password='123456', date=null}}Order{id=7, orderTime=Wed Apr 20 00:00:00 CST 2022, total=4545.0, user=User{id=2, username='lisi', password='123465', date=null}}Order{id=8, orderTime=Thu Apr 14 00:00:00 CST 2022, total=4222.0, user=User{id=1, username='张三', password='123456', date=null}}Order{id=9, orderTime=Thu May 26 00:00:00 CST 2022, total=1111.0, user=User{id=1, username='张三', password='123456', date=null}}Order{id=10, orderTime=Thu Apr 07 00:00:00 CST 2022, total=4545.0, user=User{id=1, username='张三', password='123456', date=null}}*/    }

  9.3.2、一对多模型查询

  用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户
  一对多查询的需求:查询一个用户,与此同时查询出该用户具有的订单

UserMapper中的注解配置:

 @Select("select * from user_u")    @Results({//     id=true给该列添加主键标识     @Result(id=true,column = "id",property = "id"),     @Result(column = "username",property = "username"),     @Result(column = "password",property = "password"),     @Result(      property = "orders",//属性名      column = "id",//被取出进行查询的参数,就user中的id,用于查询order      javaType = List.class,//类型为集合      many = @Many(select = "com.study.mapper.OrderMapper.findByUid")//多对多的关系     )    })    public List<User> findUserAndOrderAll();

OrderMapper中的注解配置:

@Select("select * from `order` where uid = #{uid}")    public Order findByUid(int uid);

测试结果:

 @Test    public void test() { List<User> userAndOrderAll = mapper.findUserAndOrderAll(); for (User user : userAndOrderAll) {     System.out.println(user); } /*User{id=1, username='张三', password='123456', birthday=null, orders=[Order{id=6, orderTime=Wed Apr 20 00:00:00 CST 2022, total=0.0, user=null}, Order{id=8, orderTime=Thu Apr 14 00:00:00 CST 2022, total=4222.0, user=null}, Order{id=9, orderTime=Thu May 26 00:00:00 CST 2022, total=1111.0, user=null}, Order{id=10, orderTime=Thu Apr 07 00:00:00 CST 2022, total=4545.0, user=null}]}User{id=2, username='lisi', password='123465', birthday=null, orders=[Order{id=7, orderTime=Wed Apr 20 00:00:00 CST 2022, total=4545.0, user=null}]}User{id=4, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=5, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=6, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=7, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=8, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=9, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=10, username='周瑜', password='45454545', birthday=null, orders=[]}User{id=11, username='周瑜', password='45454545', birthday=null, orders=[]}*/    }

  9.3.3、多对多查询模型

  用户表和角色表的关系为,一个用户有多个角色,一个角色被多个用户使用
  多对多查询的需求:查询用户同时查询出该用户的所有角色

注解配置

public interface UserMapper {    @Select("select * from user")    @Results({ @Result(id = true,property = "id",column = "id"), @Result(property = "username",column = "username"), @Result(property = "password",column = "password"), @Result(property = "birthday",column = "birthday"), @Result(property = "roleList",column = "id",  javaType = List.class,  many = @Many(select = "com.itheima.mapper.RoleMapper.findByUid"))})List<User> findAllUserAndRole();}public interface RoleMapper {    @Select("select * from role r,user_role ur where r.id=ur.role_id and ur.user_id=#{uid}")    List<Role> findByUid(int uid);}

测试结果:

 private UserMapper mapper;    @Before    public void before() throws IOException { //加载核心配置文件 InputStream resourceAsStream = Resources.getResourceAsStream("sqlMapConfig.xml"); //获取SQLSessionFactory对象 SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream); //获取SQLSession对象 SqlSession sqlSession = sqlSessionFactory.openSession(); //获取代理实例  mapper = sqlSession.getMapper(UserMapper.class);    }    @Test    public void testRoleAndUser() { List<User> userAndRoleAll = mapper.findUserAndRoleAll(); for (User user : userAndRoleAll) {     System.out.println(user); } /*User{id=1, username='张三', password='123456', birthday=null, orders=null, roleList=[Role{id=1, roleName='院长', roleDesc='管理学院'}, Role{id=3, roleName='教授 ', roleDesc='讲授知识'}]}User{id=2, username='lisi', password='123465', birthday=null, orders=null, roleList=[Role{id=2, roleName='副院长', roleDesc='辅助管理学院'}]}User{id=4, username='周瑜', password='45454545', birthday=null, orders=null, roleList=[Role{id=3, roleName='教授 ', roleDesc='讲授知识'}]}*/    }

在这里插入图片描述

女主播