mysql这种关系型数据库,具有强一致性,例如被外键关联的主键无法删除

一、ORM介绍

ORM即Object Relational Mapping:对象关系映射
指的是持久化数据和实体对象的映射模式,为了解决面向对象与关系型数据库存在的不匹配的现象的技术

二、Mybatis框架介绍

  1. Mybatis是一个基于java的持久层框架,它内部封装了JDBC,使开发者只需要关注SQL本身,而不需要花费精力去处理加载驱动,创建连接等
  2. 采用XML或者注解的方式将需要执行的各种Statement对象封装起来
  3. 采用ORM思想,将数据表数据封装到Java对像中

    三、Mybatis入门程序

  • 第一步:编写实体类 ```java package com.study.domain;

import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import java.io.Serializable; @Data//这个注解会加上get/set/toString/equals/hashcode()这些方法 @AllArgsConstructor @NoArgsConstructor @Builder public class Student { private Integer id; private String username; private String password; }

  1. - 第二步:编写映射配置文件(用来编写执行的SQL指定实体类和表之间的映射关系)
  2. ```xml
  3. <!DOCTYPE mapper
  4. PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  5. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  6. <mapper namespace="StudentMapper">
  7. <select id="findAll" resultType="com.study.domain.Student">
  8. SELECT * FROM jdbctest
  9. </select>
  10. </mapper>
  • 第三步:编写核心配置文件,引入映射配置文件,配置相关连接信息和其他自定义配置等

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
          PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
          "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
      <environments default="mysql">
          <environment id="mysql">
              <transactionManager type="JDBC"></transactionManager>
              <dataSource type="POOLED">
                  <property name="driver" value="com.mysql.jdbc.Driver"/>
                  <property name="url" value="jdbc:mysql://182.92.71.236:3306/study"/>
                  <property name="username" value="root"/>
                  <property name="password" value="zhubowenmysql"/>
              </dataSource>
          </environment>
      </environments>
      <mappers>
          <mapper resource="studentMapper.xml"/>
      </mappers>
    </configuration>
    
  • 第四步:编写Java代码引入核心配置文件 ```java package com.study;

import com.study.domain.Student; 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;

//Mybatis入门测试 public class MybatisTest { public static void main(String[] args) throws Exception{ //org.apache.ibatis.io.Resources他就是Mybatis提供的一个读取配置文件的工具类 //底层也是调用的类加载器的getResourceAsStream,我们也可以自己写 // InputStream resourceAsStream = Resources.getResourceAsStream(“mybatisConfig.xml”); //自定义读取配置文件输入流 InputStream resourceAsStream =MybatisTest.class.getClassLoader().getResourceAsStream(“mybatisConfig.xml”);

    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    List<Student> students = sqlSession.selectList("StudentMapper.findAll");
    for (Student student : students) {
        System.out.println(student);
    }

}

}

<a name="fqOjd"></a>
### 四、Mybatis相关API(入门程序中的)
<a name="NaY2l"></a>
#### 4.1Resources
这是Mybatis提供的一个工具类,用来加载配置文件的,底层是通过类加载器调用同样的getResourceAsStream()方法来获取配置文件的输入流<br />![读取配置文件工具类.jpg](https://cdn.nlark.com/yuque/0/2021/jpeg/21719173/1625980869392-91a0abbc-9c04-47ec-a4f2-a14109db08a6.jpeg#height=376&id=XQWpA&margin=%5Bobject%20Object%5D&name=%E8%AF%BB%E5%8F%96%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E5%B7%A5%E5%85%B7%E7%B1%BB.jpg&originHeight=376&originWidth=1290&originalType=binary&ratio=1&size=54900&status=done&style=none&width=1290)
<a name="QGulH"></a>
### 4.2、SqlSessionFactoryBuilder
它是获取SqlSessionFactory工厂类的功能类(通过这个类可以获取SessionFactory工厂),我们执行SQL需要使用的是SqlSession对象,这个对象需要SqlSessionFactory工厂对象获取

![sqlSessionFactoryBuilder对象介绍.jpg](https://cdn.nlark.com/yuque/0/2021/jpeg/21719173/1625982601316-a5e26f98-ab4d-4c92-961e-dd2645250e96.jpeg#height=361&id=yGELV&margin=%5Bobject%20Object%5D&name=sqlSessionFactoryBuilder%E5%AF%B9%E8%B1%A1%E4%BB%8B%E7%BB%8D.jpg&originHeight=361&originWidth=1275&originalType=binary&ratio=1&size=62764&status=done&style=none&width=1275)
<a name="Fe0sd"></a>
#### 4.3、SqlSessionFactory对象
这个对象是用来获取SQLSession对象,类似于JDBC中的Connection对象,同时可以用来开启事务的提交方式<br />![SqlSessionFactory对象.jpg](https://cdn.nlark.com/yuque/0/2021/jpeg/21719173/1625982752831-0aa43153-9b44-430b-a646-a819756c0134.jpeg#height=444&id=hgkQf&margin=%5Bobject%20Object%5D&name=SqlSessionFactory%E5%AF%B9%E8%B1%A1.jpg&originHeight=444&originWidth=1328&originalType=binary&ratio=1&size=75889&status=done&style=none&width=1328)
<a name="BUubN"></a>
#### 4.4、SQLSession对象
这个对象是用来执行SQL,管理事务,进行接口代理<br />![SqlSession对象.jpg](https://cdn.nlark.com/yuque/0/2021/jpeg/21719173/1625982954375-48e0a4e4-b5a8-43fa-b2aa-101a974e6fa4.jpeg#height=762&id=WhqKh&margin=%5Bobject%20Object%5D&name=SqlSession%E5%AF%B9%E8%B1%A1.jpg&originHeight=762&originWidth=1324&originalType=binary&ratio=1&size=144183&status=done&style=none&width=1324)
<a name="UE0pC"></a>
### 五、Mybatis映射配置文件
**注意:映射配置文件就是用来执行相关SQL语句,并把执行结果封装到实体类中,所以所以映射配置文件需要配置需执行的SQL和表数据和实体类之间的映射关系**
<a name="fykdz"></a>
#### 5.1、映射配置文件介绍(增删改查)
**映射配置文件相关规则:**<br />映射配置文件包含了数据和对象之间的映射关系,以及要执行的SQL语句<br />在映射配置文件中:查询用select标签,新增用insert,修改用update,删除用delete标签<br />通过#{属性名来获取参数},即我们要传递参数到SQL语句中的那个属性名字,这种方式就是JDBC的预编译方式,SQL提前编译好,#{}作为参数传递,可以防止SQL注入攻击,缺点是实现模糊查询很麻烦,需要将参数拼接%<br />${属性名来获取参数},和#{}功能类似,也是取参数放入SQL语句中,但是这种方式是采用字符串拼接的方法,缺点会出现SQL注入攻击,优点是在进行模糊查询的时候,不需要将传递的参数拼接%,直接在SQL语句中拼接<br />我们通过#{}或者${}来获取参数时,一般都是通过${属性名}或者#{属性名},如果参数集是map集合,那么就通过#{key}或者${key}来获取,如果参数的属性是一个对象,那么就通过#{对象属性名.属性名},${...}例如#{user.age}<br />注意:我们在写动态SQL的修改时,需要使用<set>标签,它会自动去掉最后一个逗号
```java
<?xml version="1.0" encoding="utf-8"?><!--xml文件的约束头-->
<!--Mybatis配置文件的DTD约束:有了这个约束,可以进行相关的提示,例如标签写错了,就可以进行报错提示-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper:它是跟标签
        namespace:命名空间
-->
<mapper namespace="StudentMapper">
<!--
select标签表示这是查询的功能
 id属性,是唯一标识通过namespace+id的方式来找到唯一的SQL语句
 resultType:表示结果集对象,是用将查询结果封装到对象中
  parameterType:用来执行参数类型
-->
    <select id="findAll" resultType="com.study.domain.Student">
        SELECT *  FROM jdbctest
    </select>
<!--查询单个,这里的结果集对象使用别名-->
    <select id="findOne" resultType="student" parameterType="java.lang.Integer">
        select * from jdbctest where id =#{id}
    </select>
<!--    新增操作-->
    <insert id="insert" parameterType="com.study.domain.Student">
        insert into jdbctest values(#{id},#{username},#{password})
    </insert>
<!--    修改功能-->
    <update id="update" parameterType="com.study.domain.Student">
        update  jdbctest set username=#{username},password=#{password} where id=#{id}
    </update>
<!--修改功能:还可以使用动态SQL写,不为null就修改,这里需要使用<set>标签,它会去掉最后一个逗号-->  
        <update id="update" parameterType="student">
        update jdbctest
        <set>
            <if test="username!=null">
                username=#{username},
            </if>
            <if test="password!=null">
                password=#{password},
            </if>
        </set>
        <where>
            id =#{id}
        </where>
    </update>

<!--    删除功能-->
    <delete id="delete" parameterType="java.lang.Integer">
        delete from jdbctest where id=#{id}
    </delete>
</mapper>
package com.study;

import com.study.domain.Student;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.InputStream;

public class MybatisTestOne {
    private SqlSession sqlSession;

    @Before
    public void getSqlSession(){
        InputStream resourceAsStream = MybatisTestOne.class.getClassLoader().getResourceAsStream("mybatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(resourceAsStream);
        sqlSession = sqlSessionFactory.openSession();
    }
    @Test
    public void test(){
        //加载核心配置文件
        Student student = sqlSession.selectOne("StudentMapper.findOne", 1);
        System.out.println(student);
        sqlSession.close();
    }
    @Test
    public void testInsert(){
        Student student = new Student();
        student.setId(9);
        student.setUsername("mybatis");
        student.setPassword("test");
        int insert = sqlSession.insert("StudentMapper.insert", student);
        //提交事务
        sqlSession.commit();
        System.out.println(insert);
        sqlSession.close();
    }
    @Test
    public void testUpdate(){
        Student student = new Student();
        student.setId(9);
        student.setUsername("朱博文");
        student.setPassword("你好");
        sqlSession.update("StudentMapper.update",student);
        sqlSession.commit();
        sqlSession.close();
    }

    @Test
    public void testDeleteFrom(){
        sqlSession.delete("StudentMapper.delete",9);
        sqlSession.commit();
        sqlSession.close();
    }
}

5.2、核心配置文件的介绍

注意:Mybatis核心配置文件,不同的配置上下是有顺序的
Mybatis核心配置文件包含了Mybatis最核心的设置和属性信息,如数据库连接,事务,连接池信息等
起别名的配置,在映射配置文件中,我们每次封装结果到实体类的时候都需要写类的全路径,很麻烦,可以通过在核心配置文件中给对应的类起别名,这样我们就可以在映射配置文件中使用别名,如果使用包扫描的方式起别名,那么这些别名就是类型名首字母小写

<?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>
<!-- 引入外部配置文件-->
<properties resource="dev/jdbc.properties"/>

  <!--   typeAliases 起别名-->
 <typeAliases>
<!-- typeAlias给单个类起别名,type表示给那个类起别名,alias表示别名    -->
<!--     <typeAlias type="com.study.domain.Student" alias="student"/>-->
<!--     package表示给指定路径下所有类起别名:name属性表示具体路径-->
     <package name="com.study.domain"/>
<!---->
 </typeAliases>

<!--    用来指定数据库环境
数据库环境可以配置多个,通过default这个属性来引入使用那个环境
-->
    <environments default="mysql">
<!--
environment:是用来配置数据环境的,可以配置多个,id就是唯一标识-->
        <environment id="mysql">
<!--transactionManager:用来配置事务的管理,type=JDBC表示使用JDBC事务管理-->
            <transactionManager type="JDBC"></transactionManager>
<!--dataSource代表数据源信息,是用来配置数据库连接的:type值为POOLED表示使用连接池)-->
            <dataSource type="POOLED">
<!-- property:表示配置数据库连接信息-->
                <property name="driver" value="${driver}"/>
                <property name="url" value="${url}"/>
                <property name="username" value="${username}"/>
                <property name="password" value="${password}"/>
            </dataSource>
        </environment>
    </environments>
<!--    mappers用来引入映射配置文件,可以引入多个,写多个mapper子标签来进行引入-->
    <mappers>
        <mapper resource="studentMapper.xml"/>
    </mappers>
</configuration>

对于Mybatis也有自带的别名供我们使用
mybatis自带别名.jpg

5.3mybatis整合log4j来打印执行的SQL

Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:
SLF4J
Apache Commons Logging
Log4j 2
Log4j
JDK logging
具体选择哪个日志实现工具由MyBatis的内置日志工厂确定。它会使用最先找到的(按上文列举的顺序查找)。 如果一个都未找到,日志功能就会被禁用。
不少应用服务器的classpath中已经包含Commons Logging,如Tomcat和WebShpere, 所以MyBatis会把它作为具体的日志实现。记住这点非常重要。这将意味着,在诸如 WebSphere的环境中——WebSphere提供了Commons Logging的私有实现,你的Log4J配置将被忽略。 这种做法不免让人悲催,MyBatis怎么能忽略你的配置呢?事实上,因Commons Logging已经存 在了,按照优先级顺序,Log4J自然就被忽略了!
具体使用

  • 导入log4j的jar包,
  • 配置log4j的配置文件 ```xml

    设置

    log4j.rootLogger = debug,stdout,D,E

    输出信息到控制抬

    log4j.appender.stdout = org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target = System.out log4j.appender.stdout.layout = org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern = [%-5p] %d{yyyy-MM-dd HH:mm:ss,SSS} method:%l%n%m%n

输出DEBUG 级别以上的日志到=E://logs/error.log

log4j.appender.D = org.apache.log4j.DailyRollingFileAppender

log4j.appender.D.File = E://logs/log.log

log4j.appender.D.Append = true

log4j.appender.D.Threshold = DEBUG

log4j.appender.D.layout = org.apache.log4j.PatternLayout

log4j.appender.D.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n

输出ERROR 级别以上的日志到=E://logs/error.log

log4j.appender.E = org.apache.log4j.DailyRollingFileAppender

log4j.appender.E.File =E://logs/error.log

log4j.appender.E.Append = true

log4j.appender.E.Threshold = ERROR

log4j.appender.E.layout = org.apache.log4j.PatternLayout

log4j.appender.E.layout.ConversionPattern = %-d{yyyy-MM-dd HH:mm:ss} [ %t:%r ] - [ %p ] %m%n


- 这核心配置文件中配置 加入settings配置,settings是用来配置Mybatis运行时行为 的,比如配置缓存,配置延迟加载等
```xml
 <settings>
        <!--    配置日志打印-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

六、Mybatis接口代理方式开发dao层

对于传统的Dao层,我们需要写接口进行约束,然后在写实现类,对于Mybatis我们只写接口,具体的实现类由Mybatis提供
要想实现接口代理方式,必须实现以下规则:

  • 映射配置文件中的命名空间必须和接口的全类名一致
  • 映射配置文件中增删改查标签的id值必须和接口中的方法名相同
  • 映射配置文件中的parameterType属性值必须和Dao层接口方法中的参数类型相同
  • 映射配置文件中的ResultType属性必须和Dao层接口方法的返回值类型相同

代码演示:
映射配置文件(核心配置文件一定要引入映射配置文件)

<?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.study.dao.PersonDao">
    <select id="findAll" resultType="com.study.domain.Person">
        select * from jdbctest
    </select>
    <select id="findById" parameterType="java.lang.Integer" resultType="com.study.domain.Person">
        select * from jdbctest where id =#{id}
    </select>
</mapper>

dao层接口

package com.study.dao;
import com.study.domain.Student;
import java.util.List;
public interface PersonDao {
    List<Student> findAll();
    Student findById(Integer id);
}

测试类

package com.study;

import com.study.dao.PersonDao;
import com.study.domain.Person;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

import java.io.InputStream;
//测试Mybatis接口代理方式开发Dao层
public class InterfaceProxyTest {
    @Test
    public void testFindAll(){
        //加载核心配置文件
        InputStream rs = InterfaceProxyTest.class.getClassLoader().getResourceAsStream("mybatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(rs);
        SqlSession sqlSession = sqlSessionFactory.openSession();
        //获取接口代理实现类对象
        PersonDao mapper = sqlSession.getMapper(PersonDao.class);
        mapper.findAll();
        sqlSession.close();
    }
}

我们在使用接口代理开发时,需要在核心配置文件通过来引入映射配置文件,没有一个mapper层接口就需要引入一次很麻烦,可以通过 来实现批量引入,将整个mapper层接口对应的配置文件都引入,这样操作的前提是映射配置文件名和mapper层接口名相同,且目录接口层级相同

七、源码分析:动态代理对象时如何生成

Mybatis通过动态代理的方式产生代理对象,底层使用的JDK动态代理来产生代理对象
方法执行源码分析:
代理对象底层最终调用的是mapperMethod.excute()方来执行,这个方法里面通过switch语句更据操作的类型最终来判断是调用什么方法,最终调用还是JDBC中SqlSession中的原生方法来执行SQL

八、Mybatis实现动态SQL

有的时候我们查询条件不同,需要执行的SQL也不同,这个 时候针对不同的条件需要写不同的SQL很麻烦,我们可以使用动态SQL的方式实现,根据查询条件的不同,产生的查询SQL也不同

8.1动态SQL标签

1.标签,它用来替代SQL语句中的where关键字,也就是说如果需要条件查询,需要将条件加入这个标签中,
2.标签,它是用来做些条件判断,即用来实现动态SQL,使用格式

查询条件拼接,

如果条件满足,那么就会将if标签里的条件拼接到SQL语句中

 <select id="findByIds" parameterType="java.lang.Integer" resultType="com.study.domain.Person">
        select * from jdbctest 
        <where>
            <if test="id !=null">
                id=#{id}
            </if>
            <if test="name !=null">
                name=#{name}
            </if>
        </where>
    </select>

3.foreach标签
如果条件是一个list集合或者数组是,需要遍历,将结果拼接到SQL语句中,这个时候需要Foreach标签

collection=参数的集合容器:如果参数在集合中用list,如果参数在数组中用array
open表示遍历之前拼接的SQL,必须使用 id in(1,2,3)那么open就需要填id in (
close表示遍历条件结束后需要拼接,一般拼接)
item表示集合中取出每个元素需要的变量,我们在里使用#{变量}来取集合中的值
separator:表示分割符,即遍历集合中的元素在SQL中使用什么分隔符分割

 select * from jdbctest
        <where>
            <foreach collection="list" open="id in(" close=")" item="param" separator="," >
                #{param}
            </foreach>
        </where>
   它就相当于select * from jdbctest where id in(1,2,3)

4.标签,当映射配置文件中又很多重复的SQL语句,我们使用标签进行抽取,格式
抽取的SQL片段
通过

 <sql id="test">select * from jdbctest</sql>
<include refid="test"/> where id =#{id}

九、MyBatis分页插件

Mybatis支持引入第三方的插件使用,需在核心配置文件中配置
步骤:

  • 第一步:导入jar包(这是第三方提供的)

    <dependency>
              <groupId>com.github.pagehelper</groupId>
              <artifactId>pagehelper</artifactId>
              <version>5.1.8</version>
          </dependency>
    
  • 第二步:在核心配置文件中配置:这个配置需要在起别名下方配置

    <plugins>
       <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
    </plugins>
    
  • 第三步:使用API进行分页操作

在需要执行分页的查询的SQL上面添加PageHelper.startPage(1,3)这个方法,这个分页不同于SQL语句的分页,这个分页第一页就是1,它是从1开始,

//查询第一页,每页显示3条数据
        PageHelper.startPage(1,3);
        mapper.findAll();
  • 第四步:获取分页参数

通过上面的方法,我们执行SQL的查询结果就会被分页,我们通过创建PageInfo对象,可以获取相关的分页参数

        //进行分页查询查询第一页,每页显示3条数据
        PageHelper.startPage(1,3);
        List<Person> list=mapper.findAll();    
        //分装分页结果:这个里的PageInfo泛型写我们查询结果的泛型,构造器传入查询的结果
        //就可以创建我们的分页对象,通过分页对象就可以获取相关的分页参数了
        PageInfo<Person> personPageInfo = new PageInfo<Person>(list);

十、Mybatis多表查询

Mybatis的多表查询,体现在查询结果的封装上,例如:我们进行一对一查询,一个类的对象作为另一个类的属性出现,那么这个属性我也需要将查询的结果封装进去,使用Mybatis就可以实现这一功能,也是就我们需要resultMap手动的配置映射关系即可
resultMap是用来配置映射关系,即当查询结果列名和对象属性名不一致时

10.1、多表关系的建立规则

一对一:在任意一方建立外键关联另一方主键,在Java中体现在一个类对象作为另一个类的属性出现
一对多:在多的一方建立外键关联一的一方主键,在java中体现在多的一方对象的List集合作为一的一方的属性
多对多:使用中间表,通过中间表外键关联两边主键

10.2一对一多表查询:

package com.study.domain;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private Integer id;
    private String name;
    private Card card;
}
public class Card {
    private Integer id;
    private Integer pid;//外键
}
<!--
resultMap:用来指定映射关系(当数据库了列名和类属性名不一致时需要使用resultMap)
id:表示唯一标识,供其他查询结果集进行引用,type表示封装的数据类型(即将结果封装成给那个类)
-->
    <resultMap id="test" type="person">
<!--id标签用来指定主键映射关系,column表示查询结果中主键的列名,property表示封装给类的那个属性 -->
        <id column="pid" property="id"/>
<!--result标签用来封装非主键的列,column表示查询结果的列名,property表示封装给类的那个属性-->
        <result column="pname" property="name"/>
<!--association这个标签是用来给类的属性对象赋值,property表示对象的属性名,javaType表示对象的类型-->
        <association property="card" javaType="com.study.Card">
<!-- 这里面的标签和resultMap里的用法相同-->
            <id column="cid" property="id"/>
            <result column="cname" property="name"/>
            <result column="cid" property="cid"/>
        </association>
    </resultMap>
<!-- 由于结果既包含多个对象属性,他们之间有重名的,所以需要resultMap来指定映射关系
同时类的属性是个对象,我们需要resultMap里面进行对象的封装
-->
    <select id="findById" parameterType="java.lang.Integer" resultMap="test">
        select p.id pid,p.name pname,c.id cid,c.name cname from person p,card c where p.id=c.pid and p.id=#{id};
    </select>

总结:一对一查询,由于查询结果的字段和对象属性名一致,所以我们需要resultMap进行执行映射关系,与此同时,我们还需要给查询结果的实体类的属性是对象类型的类赋值,这个时候就需要使用 标签进行指定映射关系

10.3、一对多表查询

package com.study.domain;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Person {
    private Integer id;
    private String name;
    private List<Sun> sunList;
}
public class Sun {
    private Integer id;
    private Integer pid;//外键
}
<!--
一对多的查询封装,和一对一的差不多,也是因为结果和属性值不同,需要使用resultMap指定映射关系
   -->
    <resultMap id="oneToMany" type="com.study.Person">
        <id column="pid" property="id"/>
        <result column="pname" property="name"/>
<!--这里封装对象的属性,但是这个属性是一个List集合,所以不能使用association标签,需要使用collection
标签,给属性是集合的对象进行封装结果
collection的属性1:property它是要封装的集合对象在类中的属性的变量名
            属性2:ofType表示集合的泛型类型
-->
        <collection property="sunList" ofType="sun">
<!-- 这里配置的映射关系就和resultMap里一样了-->
            <id column="sid" property="id"/>
            <result column="sname" property="name"/>
            <result column="spid" property="pid"/>
        </collection>
    </resultMap>
    <select id="selectAll" parameterType="java.lang.Integer" resultMap="oneToMany">
        select p.id pid,p.name pname ,s.id sid,s.name sname,s.pid spid  from person p,sun s where p.id=s.pid;
    </select>

总结:一对多的封装和一对一的封装差不多,只是在给集合属性指定映射关系是使用的是

10.4、多对多

对于多对多,站在一方看还是一对多,所以他查询结果的封装和一对多是一样的
mybatis多表操作小结.jpg

十一、mybatis注解开发

注意:我们使用注解开发多表操作时,都是使用单表查询,即我们mapper层接口上的查询都是查询单张表的数据,然后通过column这个属性来指定查询这个表的关联列(同时也会传递参数),然后通过one=@One或者many=@Many来应用其他mapper层接口的查询方法(这里的方法要写全路径),多表查询Mapper层接口上就是查询单张表一个中间表

11.1、常用的单表操作的注解

mybatis单表操作的注解.jpg
注解开发,SQL语句中使用EL表达式从方法形参中取值#{形参名}
基于注解开发步骤:

  • 第一步:提供mapper层接口
  • 在接口上通过注解写SQL语句 ```java public interface StudentMapper { //查询全部 @Select(“SELECT * FROM student”) public abstract List selectAll();

    //新增操作 @Insert(“INSERT INTO student VALUES (#{id},#{name},#{age})”) public abstract Integer insert(Student stu);

    //修改操作 @Update(“UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}”) public abstract Integer update(Student stu);

    //删除操作 @Delete(“DELETE FROM student WHERE id=#{id}”) public abstract Integer delete(Integer id); }


- 在核心配置文件中添加包扫描扫描到Mapper层接口
```xml
<mappers>
  <!--这里原来是引入映射配置文件的,但是我们使用注解开发,这里添加的就是Mapper层接口路径-->
        <package name="com.study.mapper"/>
    </mappers>

11.2、多表操作常用注解

图片10.png图片11.png

//一对一
@Results:封装映射关系的父注解。//用来封装结果集
    Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。//用来执行映射关系
    column 属性:查询出的表中字段名称
    property 属性:实体对象中的属性名称
    javaType 属性:被包含对象的数据类型
    one 属性:一对一查询固定属性
 @One:一对一查询的注解。
    select 属性:指定调用某个接口中的方法
 //一对多   
 @Results:封装映射关系的父注解。
    Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
    column 属性:查询出的表中字段名称
    property 属性:实体对象中的属性名称
    javaType 属性:被包含对象的数据类型
    many 属性:一对多查询固定属性
@Many:一对多查询的注解。
    select 属性:指定调用某个接口中的方法

 //多对多:多对多和一对多是一样的
 @Results:封装映射关系的父注解。
    Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
    column 属性:查询出的表中字段名称
    property 属性:实体对象中的属性名称
    javaType 属性:被包含对象的数据类型
    many 属性:一对多查询固定属性
@Many:一对多查询的注解。
    select 属性:指定调用某个接口中的方法

11.3注解开发多表操作—-一对一

public interface CardMapper {
    //查询全部
    @Select("SELECT * FROM card")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "number",property = "number"),
            @Result(
                    property = "p",             // 被包含对象的变量名
                    javaType = Person.class,    // 被包含对象的实际数据类型
                    column = "pid",             // 根据查询出的card表中的pid字段来查询person表
                    /*
                        one、@One 一对一固定写法
                        select属性:指定调用哪个接口中的哪个方法
                     */
                    one = @One(select = "com.itheima.one_to_one.PersonMapper.selectById")
            )
    })
    public abstract List<Card> selectAll();
}

11.4、注解开发多表操作—-一对多

public interface ClassesMapper {
    //查询全部
    @Select("SELECT * FROM classes")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(
                    property = "students",  // 被包含对象的变量名
                    javaType = List.class,  // 被包含对象的实际数据类型
                    column = "id",          // 根据查询出的classes表的id字段来查询student表
                    /*
                        many、@Many 一对多查询的固定写法
                        select属性:指定调用哪个接口中的哪个查询方法
                     */
                    many = @Many(select = "com.itheima.one_to_many.StudentMapper.selectByCid")
            )
    })
    public abstract List<Classes> selectAll();
}

11.5、注解开发多表操作——多对多

public interface StudentMapper {
    //查询全部
    @Select("SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id")
    @Results({
            @Result(column = "id",property = "id"),
            @Result(column = "name",property = "name"),
            @Result(column = "age",property = "age"),
            @Result(
                    property = "courses",   // 被包含对象的变量名
                    javaType = List.class,  // 被包含对象的实际数据类型
                    column = "id",          // 根据查询出student表的id来作为关联条件,去查询中间表和课程表
                    /*
                        many、@Many 一对多查询的固定写法
                        select属性:指定调用哪个接口中的哪个查询方法
                     */
                    many = @Many(select = "com.itheima.many_to_many.CourseMapper.selectBySid")
            )
    })
    public abstract List<Student> selectAll();
}

十二、Mybatis的构建SQL语句

对于注解开发,我们都是通过硬编码的形式写在注解里的,这是一种方式,mybatis还提供了一种构建SQL的方式,就是通过API的方式
mybatis构建SQL的api.jpg
即通过调用方法来拼接SQL语句,我们可以自定义拼接SQL的方法,然后通过注解来替换以前的注解

3.2 查询功能的实现

  • 定义功能类并提供获取查询的 SQL 语句的方法。
  • @SelectProvider:生成查询用的 SQL 语句注解。//使用这个注解来替换@Select这个注解
    type 属性:生成 SQL 语句功能类对象
    method 属性:指定调用方法

    3.3 新增功能的实现

  • 定义功能类并提供获取新增的 SQL 语句的方法。

  • @InsertProvider:生成新增用的 SQL 语句注解。 //使用这个注解来替换@Insert注解
    type 属性:生成 SQL 语句功能类对象
    method 属性:指定调用方法

    3.4 修改功能的实现

  • 定义功能类并提供获取修改的 SQL 语句的方法。

  • @UpdateProvider:生成修改用的 SQL 语句注解。 //使用这个注解来替换@Update注解
    type 属性:生成 SQL 语句功能类对象
    method 属性:指定调用方法

    3.5 删除功能的实现

  • 定义功能类并提供获取删除的 SQL 语句的方法。

  • @DeleteProvider:生成删除用的 SQL 语句注解。 //使用这个注解来替换@Delete注解
    type 属性:生成 SQL 语句功能类对象
    method 属性:指定调用方法