栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Java WEB】MyBatis详解

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Java WEB】MyBatis详解

个人主页:Hello Code.
本文专栏:《Java WEB从入门到实战》
Java WEB完整内容请点击前往Java WEB从入门到实战 查看
如有问题,欢迎指正,一起学习~~


文章目录

快速入门

MyBatis介绍入门程序 相关API映射配置文件

查询功能新增功能修改功能删除功能 核心配置文件

数据库连接配置文件引用起别名 Dao层的实现

传统方式接口代理方式 动态sql

if标签foreach标签SQL 片段的抽取 分页插件多表操作

一对一一对多多对多 注解开发

查询操作新增操作 注解多表操作构建SQL

查询操作新增操作修改操作删除操作


快速入门

框架是一款半成品软件,我们可以基于这个半成品软件继续开发,来完成我们的个性化需求

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

原始 JDBC 的操作问题分析

    频繁创建和销毁数据库的连接会造成系统资源浪费从而影响系统性能sql 语句在代码中硬编码,如果要修改sql语句,就需要修改 java 代码,造成代码不易维护查询操作时,需要手动将结果集中的数据封装到实体对象中增删改查操作需要参数时,需要手动将实体对象的数据设置到sql 语句的占位符
原始 JDBC 的操作问题解决方案
    使用数据库连接池初始化连接资源将sql 语句抽取到配置文件中使用反射、内省等底层操作技术,将实体与表进行属性与字段的自动映射
MyBatis 是一个优秀的基于Java的持久层框架,它内部封装了 JDBC,使开发者只需要关注 SQL 语句本身,而不需要花费精力去处理加载驱动、创建连接、创建执行者等复杂的操作MyBatis 通过xml 或注解的方式将要执行的各种 Statement 配置起来,并通过Java 对象和Statement 中 SQL 的动态参数进行映射生成最终要执行的SQL语句最后 MyBatis 框架执行完SQL 并将结果映射为 Java对象并返回。采用 ORM 思想解决了实体和数据库映射的问题,对 JDBC 进行了封装,屏蔽了 JDBC API 底层访问细节,使我们不用与 JDBC API 打交道,就可以完成对数据库的持久化操作MyBatis官网:http://www.mybatis.org 入门程序

    数据库数据准备

    导入 jar 包

    在src 下创建映射配置文件

    
    
    
        
            SELECT * FROM student
        
    
    

    在 src 下创建核心配置文件

    
    
    
    
        
            
                
                
                    
                    
                    
                    
                
            
        
        
        
            
        
    
    

    编写测试类完成相关API 的使用

    运行测试查看结果

package mybatis.study.dao;

import mybatis.study.bean.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 org.junit.Test;

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

public class StudentTest01 {
    
    @Test
    public void selectAll() throws IOException {
        // 1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

        // 2. 获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);

        // 3.通过SqlSession工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();

        // 4.执行映射配置文件中的sql语句,并接收结果
        List list = sqlSession.selectList("StudentMapper.selectAll");

        // 5.处理结果
        for(Student stu : list){
            System.out.println(stu);
        }

        // 6.释放资源
        sqlSession.close();
        is.close();
    }
}

相关API

Resources

org.apache.ibaties.io.Resources:加载资源的工具类核心方法

返回值方法名说明
InputStreamgetResourcesAsStream(String fileName)通过类加载器返回指定资源的字节输入流

除了使用这个工具类的方法,还可以使用类名.class.getClassLoader().getResourceAsStream(配置文件名.xml)获取到字节输入流对象

SqlSessionFactoryBuilder

org.apache.ibaties.session.SqlSessionFactoryBuilder:获取SqlSessionFactory 工厂对象的功能类核心方法

返回值方法名说明
SqlSessionFactorybuild(InputStream is)通过指定资源字节输入流获取SqlSession 工厂对象

SqlSessionFactory

org.apache.ibaties.srssion.SqlSessionFactory:获取SqlSession 构建者对象的工厂接口核心方法

返回值方法名说明
SqlSessionopenSession()获取SqlSession 构建者对象,并开启手动提交事务
SqlSessionopenSession(boolean autoCommit)获取SqlSession构建者对象,如果参数为true,则开启自动提交事务

SqlSession

org.apache.ibaties.session.SqlSession:构建者对象接口。用于执行SQL、管理事务、接口代理核心方法

返回值方法名说明
ListselectList(String statement,Object paramter)执行查询语句,返回List集合
TselectOne(String statement,Object paramter)执行查询语句,返回一个结果对象
intinsert(String statement,Object paramter)执行新增语句,返回影响行数
intupdate(String statement,Object paramter)执行修改语句,返回影响行数
intdelete(String statement,Object paramter)执行删除语句,返回影响行数
voidcommit()提交事务
voidrollback()回滚事务
TgetMapper(Classcls)获取指定接口的代理实现类对象
voidclose()释放资源

映射配置文件

映射配置文件包含了数据和对象之间的映射关系以及要执行的SQL语句






    
    
        SELECT * FROM student
    
    :查询功能标签属性
id:唯一标识
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型SQL 获取参数
#{属性名}

注意:属性名要和对象中的成员变量名称一致,才能获取到正确的值

新增功能

	INSERT INTO student VALUES (#{id},#{name},#{age})

@Test
public void insert() throws IOException {
    InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    Student stu = new Student(7,"老八",28);
    int result = sqlSession.insert("StudentMapper.insert", stu);
    // 如果没有开启自动提交事务,对于增删改,在执行完SQL后还需要提交事务
    // sqlSession.commit();
    System.out.println(result);
    is.close();
    sqlSession.close();
}

:新增功能标签属性
id:唯一标识,配合名称空间使用
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型

对于增删改操作,返回的的结果都是int类型的影响行数,故resultType可以省略不写

SQL获取参数
#{属性名}

注意:属性名要和对象中的成员变量名称一致,才能获取到正确的值

修改功能

	UPDATE student SET name = #{name},age = #{age} WHERe id = #{id}

@Test
public void update() throws IOException {
    InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    Student stu = new Student(6,"周七七",37);
    int result = sqlSession.insert("StudentMapper.update", stu);
    // 如果没有开启自动提交事务,对于增删改,在执行完SQL后还需要提交事务
    sqlSession.commit();
    System.out.println(result);
    is.close();
    sqlSession.close();
}

:修改功能标签属性
id:唯一标识,配合名称空间使用
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型SQL 获取参数
#{属性名} 删除功能


	DELETE FROM student WHERe id = #{id}

@Test
public void delete() throws IOException {
    InputStream is = Resources.getResourceAsStream("MybatisConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = sqlSessionFactory.openSession();
    int result = sqlSession.delete("StudentMapper.delete", 7);
    System.out.println(result);
    // 提交事务
    sqlSession.commit();
    sqlSession.close();
    is.close();
}

:删除功能标签属性
id:唯一标识,配合名称空间使用
parameterType:指定参数映射的对象类型
resultType:指定结果映射的对象类型SQL 获取参数
#{属性名}


核心配置文件

核心配置文件包含了MyBatis 最核心的设置和属性信息。如数据库的连接、事务、连接池信息等







    
    
        
        
            
            
            
            
                
                
                
                
                
            
        
    
    
    
        
        
    

数据库连接配置文件引用

为了方便修改,可以将核心配置文件中的数据库连接信息抽取出来:jdbc.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://192.168.23.129
username=root
password=密码
:使用该标签可以引入数据库连接配置文件属性
resource:数据库连接配置文件路径获取数据库连接参数
${键名}




    
    
    
        
            
            
                
                
                
                
                
            
        
    
    
        
    

起别名

:为全类名起别名的父标签:为全类名起别名的子标签属性
type:指定全类名
alias:指定别名:为指定包下所有的类起别名的子标签(别名就是类名)


	
    

在核心配置文件中起别名后,就可以简化映射配置文件中的全类名

MyBatis自带的一些别名

别名数据类型
stringjava.lang.String
longjava.lang.Long
intjava.lang.Integer
doublejava.lang.Double
booleanjava.lang.Boolean

Dao层的实现 传统方式

分层思想:控制层(controller)、业务层(service)、持久层(dao)调用流程
控制层 --> 业务层 --> 持久层 --> DB

在MyBatis中,持久层叫mapper

package mybatis.study.mapper;

import mybatis.study.bean.Student;

import java.util.List;




public interface StudentMapper {
    // 查询全部
    public abstract List selectAll();

    // 根据id查询
    public abstract Student selectById(Integer id);

    // 新增数据
    public abstract Integer insert(Student stu);

    // 修改数据
    public abstract Integer update(Student stu);

    // 删除数据
    public abstract Integer delete(Integer id);
}
package mybatis.study.mapper.impl;

import mybatis.study.bean.Student;
import mybatis.study.mapper.StudentMapper;
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.IOException;
import java.io.InputStream;
import java.util.List;

public class StudentMapperImpl implements StudentMapper {
    @Override
    public List selectAll() {
        InputStream is = null;
        SqlSession sqlSession = null;
        List list = null;
        try{
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            list = sqlSession.selectList("StudentMapper.selectAll");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sqlSession != null){
                sqlSession.close();
            }
        }
        return list;
    }

    @Override
    public Student selectById(Integer id) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Student stu = null;
        try{
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            stu = sqlSession.selectOne("StudentMapper.selectById",id);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sqlSession != null){
                sqlSession.close();
            }
        }
        return stu;
    }

    @Override
    public Integer insert(Student stu) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try{
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            result = sqlSession.insert("StudentMapper.insert",stu);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sqlSession != null){
                sqlSession.close();
            }
        }
        return result;
    }

    @Override
    public Integer update(Student stu) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try{
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            result = sqlSession.update("StudentMapper.update",stu);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sqlSession != null){
                sqlSession.close();
            }
        }
        return result;
    }

    @Override
    public Integer delete(Integer id) {
        InputStream is = null;
        SqlSession sqlSession = null;
        Integer result = null;
        try{
            is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            sqlSession = sqlSessionFactory.openSession(true);
            result = sqlSession.delete("StudentMapper.delete",id);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if(sqlSession != null){
                sqlSession.close();
            }
        }
        return result;
    }
}
package mybatis.study.service;

import mybatis.study.bean.Student;

import java.util.List;



public interface StudentService {
    // 查询全部
    public abstract List selectAll();

    // 根据id查询
    public abstract Student selectById(Integer id);

    // 新增数据
    public abstract Integer insert(Student stu);

    // 修改数据
    public abstract Integer update(Student stu);

    // 删除数据
    public abstract Integer delete(Integer id);
}
package mybatis.study.service.impl;

import mybatis.study.bean.Student;
import mybatis.study.mapper.StudentMapper;
import mybatis.study.mapper.impl.StudentMapperImpl;
import mybatis.study.service.StudentService;

import java.util.List;

public class StudentServiceImpl implements StudentService {
    // 创建持久层对象
    private StudentMapper mapper = new StudentMapperImpl();

    @Override
    public List selectAll() {
        return mapper.selectAll();
    }

    @Override
    public Student selectById(Integer id) {
        return mapper.selectById(id);
    }

    @Override
    public Integer insert(Student stu) {
        return mapper.insert(stu);
    }

    @Override
    public Integer update(Student stu) {
        return mapper.update(stu);
    }

    @Override
    public Integer delete(Integer id) {
        return mapper.delete(id);
    }
}
package mybatis.study.controller;

import mybatis.study.bean.Student;
import mybatis.study.service.StudentService;
import mybatis.study.service.impl.StudentServiceImpl;
import org.junit.Test;

import java.util.List;


public class StudentController {
    // 创建业务层对象
    private StudentService service = new StudentServiceImpl();

    @Test
    public void selectAll(){
        List stus = service.selectAll();
        for(Student stu : stus){
            System.out.println(stu);
        }
    }

    @Test
    public void selectById(){
        Student stu = service.selectById(5);
        System.out.println(stu);
    }

    @Test
    public void insert(){
        Student stu = new Student(5,"赵六",46);
        Integer result = service.insert(stu);
        System.out.println(result);
    }

    @Test
    public void delete(){
        Integer result = service.delete(5);
        System.out.println(result);
    }

    @Test
    public void update(){
        Student stu = new Student(5,"赵六六",36);
        Integer result = service.update(stu);
        System.out.println(result);
    }
}

LOG4J

在日常开发过程中,排查问题时难免需要输出 MyBatis 真正执行的 SQL语句、参数、结果等信息,我们就可以借助 LOG4J 的功能来实现执行信息的输出使用步骤

    导入jar 包修改核心配置文件
    
    	
    
    
    在 src下编写LOG4J 配置文件
    # Global logging configuration
    # 输出信息的显示。四个级别:ERROR、WARN、INFO、DEBUG
    log4j.rootLogger=DEBUG, stdout
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%n
    
接口代理方式

传统方式实现Dao层,我们既需要写接口,还要写实现类。而MyBatis 框架可以帮助我们省略编写 Dao层接口实现类的步骤。程序员只需要编写接口,由MyBatis 框架根据接口的定义来创建该接口的动态代理对象

实现规则

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

代码实现

    删除mapper层接口的实现类修改映射配置文件修改service 层接口的实现类,采用接口代理方式实现功能
 
 
 
 
     
         SELECT * FROM student WHERe id = #{id}
     
     
         INSERT INTO student VALUES (#{id},#{name},#{age})
     
     
         UPDATE student SET name = #{name},age = #{age} WHERe id = #{id}
     
     
         DELETE FROM student WHERe id = #{id}
     
 
 @Override
 public List selectAll() {
     InputStream is = null;
     List list = null;
     SqlSession sqlSession = null;
     try{
         // 1.加载核心配置文件
         is = Resources.getResourceAsStream("MyBatisConfig.xml");
         // 2. 获取SqlSessionFactory 工厂对象
         SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
         // 3. 获取SqlSession对象
         sqlSession = sqlSessionFactory.openSession(true);
         // 4.获取StudentMapper持久层接口的实现类对象
         StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
         // 5.通过实现类对象调用方法,接收结果
         list = mapper.selectAll();
     }catch (Exception e){
         e.printStackTrace();
     }finally {
         // 6.释放资源
         if(sqlSession != null){
             sqlSession.close();
         }
         if(is != null){
             try {
                 is.close();
             } catch (IOException e) {
                 e.printStackTrace();
             }
         }
     }
     return list;
 }

通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper()方法最终获取到org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象,从而可以进行相关持久化操作

动态代理实现类对象在执行方法的时候最终调用了 mapperMethod.execute() 方法,这个方法中通过 switch语句根据操作类型来判断是新增、修改、删除、查询操作,最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查


动态sql

MyBatis 映射配置文件中,前面使用的SQL 都是比较简单的,有些时候业务逻辑复杂时,我们的 SQL就是动态变化的,此时前面学习的 SQL 就不能满足需求了多条件查询
SELECT * FROM student WHERe id = ? AND name = ? AND age = ?
SELECt * FROM student WHERe id = ? AND name = ?动态SQL 标签
:条件判断标签
:循环遍历标签 if标签

:条件标签。如果有动态条件,则使用该标签代替where 关键字:条件判断标签


    查询条件拼接


    SELECT * FROM student
    
        
            id = #{id}
        
        
            AND name = #{name}
        
        
            AND age = #{age}
        
    

foreach标签

:循环遍历标签。适用于多个参数或者的关系


    获取参数

属性
collection:参数容器类型,(list-集合,array-数组)
open:开始的 SQL 语句
close:结束的 SQL 语句
item:参数变量名
separator:分隔符



分页插件

分页可以将很多条结果进行分页显示如果当前在第一页,则没有上一页。如果在最后一页,则没有下一页需要明确当前是第几页,这一页中显示多少条结果

在企业级的开发中,分页也是一种常见的技术。而目前使用的 MyBatis 是不带分页功能的,如果想实现分页的功能,需要我们手动编写 LIMIT 语句。但是不同的数据库实现分页的 SQL 语句也是不同的,所以手写分页成本较高。这个时候可以借助分页插件来帮助我们实现分页功能

PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单

分页插件实现步骤

    导入jar 包:pagehelper-5.1.10.jar jsqlparser-3.1.jar在核心配置文件中集成分页助手插件在测试类中使用分页助手相关 API 实现分页功能

    

分页参数的获取

PageInfo:封装分页相关参数的功能类核心方法

返回值方法名说明
longgetTotal()获取总条数
intgetPages()获取总页数
intgetPageNum()获取当前页
intgetPageSize()获取每页显示条数
intgetPrePage()获取上一页
intgetNextPage()获取下一页
booleanisIsFirstPage()获取是否是第一页
booleanisIsLastPage()获取是否是最后一页
@Test
public void selectPaging() throws IOException {
    InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
    SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    SqlSession sqlSession = sqlSessionFactory.openSession(true);
    StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

    // 通过分页助手实现分页功能
    // 参数:当前页,显示的条数
    PageHelper.startPage(1,3);

    List list = mapper.selectAll();
    for(Student stu : students){
        System.out.println(stu);
    }

    //获取分页相关参数
    PageInfo info = new PageInfo<>(list);
    
    System.out.println("总条数" + info.getTotal());
    System.out.println("总页数" + info.getPages());
    System.out.println("当前页" + info.getPageNum());
    System.out.println("每页条数" + info.getPageSize());
    System.out.println("上一页" + info.getPrePage());
    System.out.println("下一页" + info.getNextPage());
    System.out.println("是否是第一页:" + info.isIsFirstPage());
    System.out.println("是否是最后一页:" + info.isIsLastPage());

    sqlSession.close();
    is.close();
}

多表操作

我们之前学习的都是基于单表操作的,二实际开发中,随着业务逻辑难度的加深,肯定需要多表操作的多表模型的分类

一对一:在任意一方建立外键,关联对方的主键一对多:在多的一方建立外键,关联少的一方的主键多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键 一对一

一对一模型:人和身份证,是一对一的关系数据准备

CREATE DATAbase db12;
USE db12;
CREATE TABLE person(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	age INT
);
INSERT INTO person VALUES (NULL,'张三',23),(NULL,'李四',24),(NULL,'王五',25);
CREATE TABLE card(
	id INT PRIMARY KEY AUTO_INCREMENT,
	number VARCHAR(30),
	pid INT,
	CONSTRAINT cp_fk FOREIGN KEY (pid) REFERENCES person(id)
);
INSERT INTO card VALUES (NULL,'12345',1),(NULL,'23456',2),(NULL,'34567',3);
映射配置文件



    
    
        
        
        
        
            
            
            
        
    
    
        SELECT c.id cid,c.name cname,s.id sid, s.name sname,s.age sage FROM classes c,student s WHERe c.id = s.cid;
    

@Test
    public void selectAll() throws IOException {
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        OneToManyMapper mapper = sqlSession.getMapper(OneToManyMapper.class);
        List classes = mapper.selectAll();
        for(Classes cls : classes){
            System.out.println(cls.getId() + "," + cls.getName());
            List students = cls.getStudents();
            for(Student stu : students){
                System.out.println("t" + stu);
            }
        }
    }

:配置字段和对象属性的映射关系标签
id属性:唯一标识
type属性:实体对象类型:配置主键映射的关系标签:配置非主键映射关系标签
column属性:表中字段名称
property属性:实体对象变量名称:配置被包含集合对象的映射关系标签
property属性:被包含集合对象的变量名
ofType属性:集合中保存的对象数据类型 多对多

多对多模型:学生和课程,一个学生可以选择多门课程,一个课程也可以被多个学生所选择数据准备

CREATE TABLE course(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20)
);
INSERT INTO course VALUES (NULL,'语文'),(NULL,'数学');
CREATE TABLE stu_cr(
	id INT PRIMARY KEY AUTO_INCREMENT,
	sid INT,
	cid INT,
	CONSTRAINT sc_fk1 FOREIGN KEY (sid) REFERENCES student(id),
	CONSTRAINT sc_fk2 FOREIGN KEY (cid) REFERENCES course(id)
);
INSERT INTO stu_cr VALUES (NULL,1,1),(NULL,1,2),(NULL,2,1),(NULL,2,2);
映射配置文件