Mybatis从入门到熟练使用、知识点汇总、案例展示

一.Mybatis入门

1.1 框架介绍
  • 框架是一款半成品软件,我们可以基于这个半成品软件继续开发,来完成我们个性化的需求!
1.2 ORM介绍
  • ORM(Object Relational Mapping): 对象关系映射

    • object:指的是实体对象,javabean
    • relational:指的是关系型数据库,比如mysql
  • 指的是持久化数据和实体对象的映射模式为了解决面向对象与关系型数据库存在的互不匹配的现象的技术

  • 简单说,ORM 就是通过实例对象的语法,完成关系型数据库的操作的技术,是"对象-关系映射"(Object/Relational Mapping)的缩写

  • ORM 把数据库映射成对象,具体映射关系如下:

    数据库的表(table) -->(class)
    记录(record,行数据) --> 对象(Object)
    字段(field) --> 对象的属性(attribute)
    
1.3 什么是Mybatis
  • mybatis 是一个优秀的基于java的持久层框架,它内部封装了jdbc,使开发者只需要关注sql语句本身,而不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程

  • mybatis通过xml或注解的方式将要执行的各种 statement配置起来,并通过java对象和statement中sql的动态参数进行映射生成最终执行的sql语句

  • 最后mybatis框架执行sql并将结果映射为java对象并返回。采用ORM思想解决了实体和数据库映射的问题,对jdbc 进行了封装,屏蔽了jdbc api 底层访问细节,使我们不用与jdbc api 打交道,就可以完成对数据库的持久化操作

1.4 Mybatis的快速入门

MyBatis开发步骤:

①添加MyBatis的jar包

②创建Student数据表

③编写Student实体类

④编写映射文件StudentMapper.xml

⑤编写核心文件MyBatisConfig.xml

⑥编写测试类

1.4.1 环境搭建
  1. 新建java项目:

  2. 导入MyBatis的jar包

  • mysql-connector-java-5.1.37-bin.jar
  • mybatis-3.5.3.jar
  • junit-4.9.jar
  1. 创建student数据表
CREATE TABLE student(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(20),
	age INT
);

INSERT INTO student VALUES 
(NULL,'张三',23),
(NULL,'李四',24),
(NULL,'王五',25);
  1. 编写Student实体
public class Student {
    private Integer id;
    private String name;
    private Integer age;    
    //Getter and Setter
}
  1. 新建测试类
public class StudentTest01 {
    /*
        查询全部
     */
    @Test
    public void selectAll() throws Exception{
        //1.加载核心配置文件

        //2.获取SqlSession工厂对象

        //3.通过SqlSession工厂对象获取SqlSession对象

        //4.执行映射配置文件中的sql语句,并接收结果

        //5.处理结果

        //6.释放资源
    }
}
  1. 编写src/StudentMapper.xml映射文件
<?xml version="1.0" encoding="UTF-8" ?>
<!--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属性:唯一标识
        resultType属性:指定结果映射对象类型
        parameterType属性:指定参数映射对象类型
    -->
    <select id="selectAll" resultType="com.lichee.bean.Student">
        SELECT * FROM student
    </select>
</mapper>
  1. 编写MyBatis核心文件: src/MyBatisConfig.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束 直接复制-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--configuration 核心根标签-->
<configuration>
    <!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
    <environments default="mysql">
        <!--environment配置数据库环境  id属性唯一标识-->
        <environment id="mysql">
            <!-- transactionManager事务管理。  type属性,采用JDBC默认的事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- dataSource数据源信息   type属性 连接池-->
            <dataSource type="POOLED">
                <!-- property获取数据库连接的配置信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/db1" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>

    <!-- mappers引入映射配置文件 -->
    <mappers>
        <!-- mapper 引入指定的映射配置文件   resource属性指定映射配置文件的名称 -->
        <mapper resource="StudentMapper.xml"/>
    </mappers>
</configuration>
1.4.2 编写测试代码
@Test
public void selectAll() throws Exception{
    //1.加载核心配置文件
    InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");

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

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

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

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

    //6.释放资源
    sqlSession.close();
    is.close();
}
1.5 知识小结
  • 框架

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

  • ORM

    对象关系映射,数据和实体对象的映射。

  • MyBatis

    是一个优秀的基于 Java 的持久层框架,它内部封装了 JDBC。

二. MyBatis的相关API

2.1 Resources
  • org.apache.ibatis.io.Resources:加载资源的工具类

    • mybatis的前身就是ibatis
  • 核心方法

    返回值方法名说明
    InputStreamgetResourceAsStream(String fileName)通过类加载器返回指定资源的字节输入流
  • 如果不使用Resources,那我们可以自己使用类加载器(但是麻烦)

    //InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
    InputStream is = StudentTest01.class.getClassLoader().getResourceAsStream("MyBatisConfig.xml");
    
2.2 构建器SqlSessionFactoryBuilder
  • org.apache.ibatis.session.SqlSessionFactoryBuilder:获取 SqlSessionFactory 工厂对象的功能类

  • 核心方法

    返回值方法名说明
    SqlSessionFactorybuild(InputStream is)通过指定资源字节输入流获取SqlSession工厂对象
  • 通过加载mybatis的核心文件的输入流的形式构建一个SqlSessionFactory对象

InputStream inputStream = Resources.getResourceAsStream("MyBatisConfig.xml"); 
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); 
SqlSessionFactory fact	ory = builder.build(inputStream);
2.3 工厂对象SqlSessionFactory
  • org.apache.ibatis.session.SqlSessionFactory:获取 SqlSession 构建者对象的工厂接口。

  • 核心api

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

     //3.通过SqlSession工厂对象获取SqlSession对象
    SqlSession sqlSession = sqlSessionFactory.openSession();
    
    //4.执行映射配置文件中的sql语句,并接收结果
    List<Student> list = sqlSession.selectList("StudentMapper.selectAll");
    
    • 说明:因为我们的代码是执行了一个查询的语句,所以不用处理事务
2.4 SqlSession会话对象
  • org.apache.ibatis.session.SqlSession:构建者对象接口。用于执行 SQL、管理事务、接口代理。

  • 核心api

    返回值方法名说明
    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(class cls)获取指定接口的代理实现类对象
    voidclose()释放资源
  • SqlSession 实例在 MyBatis 中是非常强大的一个类。在这里你会看到所有执行语句、提交或回滚事务和获取映射器实例的方法

  • 作用:

    • 通过SqlSession对象,主要用途执行sql语句,对数据库进行操作
  • 本质:

    • SqlSession 可以理解为相当于一个数据库连接(Connection 对象),你可以在一个事务里面执行多条 SQL,然后通过它的 commit、rollback 等方法,提交或者回滚事务
    • 所以它应该存活在一个业务请求中,处理完整个请求后,应该关闭这条连接,让它归还给SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭
2.5 小结
  • Resources
    • 加载资源的工具类
  • SqlSessionFactoryBuilder
    • 获取 SqlSessionFactory 工厂对象的功能类
  • SqlSessionFactory
    • 获取 SqlSession 构建者对象的工厂接口
    • 指定事务的提交方式
  • SqlSession
    • 构建者对象接口
    • 执行 SQL
    • 管理事务
    • 接口代理

三.MyBatis 映射配置文件

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

    <?xml version="1.0" encoding="UTF-8" ?>
    <!--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属性:唯一标识
            resultType属性:指定结果映射对象类型
            parameterType属性:指定参数映射对象类型
        -->
        <select id="selectAll" resultType="com.lichee.bean.Student">
            SELECT * FROM student
        </select>
    </mapper>
    
    • 这个namespace,命名空间,相当于是给这个映射节点,起一个名字
    • 内部的所有增删改查的配置,都需要通过这个命名空间获取
    • 语法:命名空间.id
3.2 查询功能
  • <select>:查询功能标签

  • 属性

    id:唯一标识, 配合名称空间使用

    parameterType:指定参数映射的对象类型

    resultType:指定结果映射的对象类型

  • SQL 获取参数:#{属性名}

  • 修改StudentMapper.xml,增加如下:

    <select id="selectById" resultType="com.lichee.bean.Student" parameterType="java.lang.Integer">
        SELECT * FROM student WHERE id = #{id}
    </select>
    
    • 因为参数类型是Integer,所以可以改名字
    • 但是这里的参数名一般是与数据库列名和Student的列名一致的
  • 测试类StudentTest01.java,新增代码:

    /*
      根据id查询
    */
    @Test
    public void selectById() throws Exception{
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
        //3.通过工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        //4.执行映射配置文件中的sql语句,并接收结果
        Student stu = sqlSession.selectOne("StudentMapper.selectById", 3);
    
        //5.处理结果
        System.out.println(stu);
    
        //6.释放资源
        sqlSession.close();
        is.close();
    }
    
3.3 新增功能
  • <insert>:新增功能标签

  • 属性

    id:唯一标识, 配合名称空间使用

    parameterType:指定参数映射的对象类型

    resultType:指定结果映射的对象类型

  • SQL 获取参数:#{属性名}

  • 修改StudentMapper.xml,增加如下:

    <insert id="insert" parameterType="com.lichee.bean.Student">
        INSERT INTO student VALUES (#{id},#{name},#{age})
    </insert>
    
    • 注意:因为这里的参数类型是Student,所以参数名必须与Student的字段保持一致
  • 测试类StudentTest01.java,新增代码:

    /*
    	新增功能
    */
    @Test
    public void insert() throws Exception{
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
        //3.通过工厂对象获取SqlSession对象
        //SqlSession sqlSession = sqlSessionFactory.openSession();
        // 自动提交事务
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
    
        //4.执行映射配置文件中的sql语句,并接收结果
        Student stu = new Student(5,"周七",27);
        int result = sqlSession.insert("StudentMapper.insert", stu);
    
        //5.提交事务(手动提交事务)
        //sqlSession.commit();
    
        //6.处理结果
        System.out.println(result);
    
        //7.释放资源
        sqlSession.close();
        is.close();
    }
    
3.4 修改功能
  • <update>:修改功能标签

  • 属性

    id:唯一标识, 配合名称空间使用

    parameterType:指定参数映射的对象类型

    resultType:指定结果映射的对象类型

  • SQL 获取参数: #{属性名}

  • 修改StudentMapper.xml,增加如下:

    <update id="update" parameterType="com.lichee.bean.Student">
        UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
    </update>
    
    • 注意:因为这里的参数类型是Student,所以参数名必须与Student的字段保持一致
  • 测试类StudentTest01.java,新增代码:

    /*
    	修改功能
    */
    @Test
    public void update() throws Exception{
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
        //3.通过工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        //4.执行映射配置文件中的sql语句,并接收结果
        Student stu = new Student(5,"周七",37);
        int result = sqlSession.update("StudentMapper.update",stu);
    
        //5.提交事务
        sqlSession.commit();
    
        //6.处理结果
        System.out.println(result);
    
        //7.释放资源
        sqlSession.close();
        is.close();
    }
    
3.5 删除功能
  • <delete>:查询功能标签。

  • 属性

    id:唯一标识, 配合名称空间使用。

    parameterType:指定参数映射的对象类型。

    resultType:指定结果映射的对象类型。

  • SQL 获取参数:#{属性名}

  • 修改StudentMapper.xml,增加如下:

    <delete id="delete" parameterType="java.lang.Integer">
        DELETE FROM student WHERE id = #{id}
    </delete>
    
  • 测试类StudentTest01.java,新增代码:

    /*
    	删除功能
    */
    @Test
    public void delete() throws Exception{
        //1.加载核心配置文件
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
        //2.获取SqlSession工厂对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
        //3.通过工厂对象获取SqlSession对象
        SqlSession sqlSession = sqlSessionFactory.openSession();
    
        //4.执行映射配置文件中的sql语句,并接收结果
        int result = sqlSession.delete("StudentMapper.delete",5);
    
        //5.提交事务
        sqlSession.commit();
    
        //6.处理结果
        System.out.println(result);
    
        //7.释放资源
        sqlSession.close();
        is.close();
    }
    
  • 总结: 可以发现crud操作,除了标签名称以及sql语句不一样之外,其他属性参数基本一致。

3.6 映射配置文件小结
  • 映射配置文件包含了数据和对象之间的映射关系以及要执行的SQL语句。
  • <mapper>:核心根标签。
    • namespace 属性:名称空间
  • <select>:查询功能标签。
  • <insert>:新增功能标签。
  • <update>:修改功能标签。
  • <delete>:删除功能标签。
    • id 属性:唯一标识,配合名称空间使用
    • parameterType 属性:指定参数映射的对象类型
    • resultType 属性:指定结果映射的对象类型
  • SQL获取参数
    • #{属性名}

四.Mybatis核心配置文件介绍

4.1 核心配置文件介绍

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

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">

<!--configuration 核心根标签-->
<configuration>

    <!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
    <environments default="mysql">
        <!--environment配置数据库环境  id属性唯一标识-->
        <environment id="mysql">
            <!-- transactionManager事务管理。  type属性,采用JDBC默认的事务-->
            <transactionManager type="JDBC"></transactionManager>
            <!-- dataSource数据源信息   type属性 连接池-->
            <dataSource type="POOLED">
                <!-- property获取数据库连接的配置信息 -->
                <property name="driver" value="com.mysql.jdbc.Driver" />
                <property name="url" value="jdbc:mysql://127.0.0.1:3306/db1" />
                <property name="username" value="root" />
                <property name="password" value="root" />
            </dataSource>
        </environment>
    </environments>

    <!-- mappers引入映射配置文件 -->
    <mappers>
        <!-- mapper 引入指定的映射配置文件   resource属性指定映射配置文件的名称 -->
        <mapper resource="StudentMapper.xml"/>
    </mappers>
</configuration>
4.2 数据库连接配置文件引入
  • properties标签作用:
    • 引入外部的数据库配置文件
  • 标签属性
    • resource:数据库连接配置文件路径
  • 获取数据库连接参数的语法格式
    • ${键名}
  • 优点
    • 便于灵活的修改数据库连接池配置参数.
  • 创建:src/jdbc.properties

    driver=com.mysql.jdbc.Driver
    url=jdbc:mysql://127.0.0.1:3306/db1
    username=root
    password=root
    
  • 修改MyBatisConfig.xml配置文件:properties标签引入外部文件

    <!--引入数据库连接的配置文件-->
    <properties resource="jdbc.properties"/>
    
    <!-- property获取数据库连接的配置信息 -->
    <property name="driver" value="${driver}" />
    <property name="url" value="${url}" />
    <property name="username" value="${username}" />
    <property name="password" value="${password}" />
    
4.3 起别名
  • <typeAliases>:为全类名起别名的父标签。

  • <typeAlias>:为全类名起别名的子标签。

  • 属性

    type:指定全类名

    alias:指定别名

  • <package>:为指定包下所有类起别名的子标签。(别名就是类名)

  • 如下图:

    别名数据类型
    stringjava.lang.String
    longjava.lang.Long
    intjava.lang.Integer
    doublejava.lang.Double
    booleanjava.lang.Boolean
  • 具体如下配置:修改MyBatisConfig.xml,增加代码如下:

    <!--起别名-->
    <typeAliases>
        <typeAlias type="com.lichee.bean.Student" alias="student"/>
        <!--<package name="com.lichee.bean"/>
      如果bean包下有很多Javabean都需要起别名,就可以使用package,指定一个包名
      这样的话,就自动给这个包下所有的类添加别名,别名是类名的小写名字
      -->
        </typeAliase>
    </typeAliases>
    
  • 然后使用的时候就方便了,修改StudentMapper.xml中的com.lichee.bean.Student

    <select id="selectAll" resultType="student">
        SELECT * FROM student
    </select>
    
    <select id="selectById" resultType="student" parameterType="int">
        SELECT * FROM student WHERE id = #{id}
    </select>
    
    <insert id="insert" parameterType="student">
        INSERT INTO student VALUES (#{id},#{name},#{age})
    </insert>
    
    <update id="update" parameterType="student">
        UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
    </update>
    
    <delete id="delete" parameterType="int">
        DELETE FROM student WHERE id = #{id}
    </delete>
    
4.4 总结
  • 核心配置文件包含了 MyBatis 最核心的设置和属性信息。如数据可得连接、事务、连接池信息等。
  • <configuration>:核心根标签。
  • <properties>:引入数据库连接信息配置文件标签。
  • <typeAliases>:起别名标签。
  • <environments>:配置数据库环境标签。
  • <environment>:配置数据库信息标签。
  • <transactionManager>:事务管理标签。
  • <dataSource>:数据源标签。
  • <property>:数据库连接信息标签。
  • <mappers>:引入映射配置文件标签。

五.Mybatis传统方式开发

5.1 Dao 层传统实现方式
  • 分层思想:控制层(controller)、业务层(service)、持久层(dao)。
  • 调用流程
  • 控制层→业务层→持久层→DB
5.1.1 准备工作
  • 实现步骤

    1. 在controller包下: 新建StudentContoller类
    2. 在service包下: 新建StudentService接口以及StudentServiceImpl实现类
    3. 在mapper包下:新建StudentMapper接口以及StudentMapperImpl实现类
    4. StudentContoller----->StudentService----->StudentMapper
  • 在mybatis项目中持久层就不再叫dao了,而是叫做mapper(其实都是一样的,就是换个名字)

  • StudentMapper接口

    /*
        持久层接口
     */
    public interface StudentMapper {
        //查询全部
        public abstract List<Student> 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);
    }
    
  • StudentMapperImpl实现类

    /*
        持久层实现类
     */
    public class StudentMapperImpl implements StudentMapper {
    
        /*
            查询全部
         */
        @Override
        public List<Student> selectAll() {
        }
    
        /*
            根据id查询
         */
        @Override
        public Student selectById(Integer id) {
        }
    
        /*
            新增功能
         */
        @Override
        public Integer insert(Student stu) {
        }
    
        /*
            修改功能
         */
        @Override
        public Integer update(Student stu) {
        }
    
        /*
            删除功能
         */
        @Override
        public Integer delete(Integer id) {
        }
    }
    
  • StudentService接口

    /*
        业务层接口
     */
    public interface StudentService {
        //查询全部
        public abstract List<Student> 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);
    }
    
  • StudentServiceImpl实现类

    /*
        业务层实现类
     */
    public class StudentServiceImpl implements StudentService {
    
        //创建持久层对象
        private StudentMapper mapper = new StudentMapperImpl();
    
        @Override
        public List<Student> 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);
        }
    }
    
  • StudentController测试类:

    /*
        控制层测试类
     */
    public class StudentController {
        //创建业务层对象
        private StudentService service = new StudentServiceImpl();
    
        //查询全部功能测试
        @Test
        public void selectAll() {
            List<Student> students = service.selectAll();
            for (Student stu : students) {
                System.out.println(stu);
            }
        }
    
        //根据id查询功能测试
        @Test
        public void selectById() {
            Student stu = service.selectById(3);
            System.out.println(stu);
        }
    
        //新增功能测试
        @Test
        public void insert() {
            Student stu = new Student(4,"赵六",26);
            Integer result = service.insert(stu);
            System.out.println(result);
        }
    
        //修改功能测试
        @Test
        public void update() {
            Student stu = new Student(4,"赵六",16);
            Integer result = service.update(stu);
            System.out.println(result);
        }
    
        //删除功能测试
        @Test
        public void delete() {
            Integer result = service.delete(4);
            System.out.println(result);
        }
    }
    
5.1.2 持久层功能实现
/*
    持久层实现类
 */
public class StudentMapperImpl implements StudentMapper {

    /*
        查询全部
     */
    @Override
    public List<Student> selectAll() {
        List<Student> list = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try{
            //1.加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");

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

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

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

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //6.返回结果
        return list;
    }

    /*
        根据id查询
     */
    @Override
    public Student selectById(Integer id) {
        Student stu = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try{
            //1.加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");

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

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

            //4.执行映射配置文件中的sql语句,并接收结果
            stu = sqlSession.selectOne("StudentMapper.selectById",id);

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //6.返回结果
        return stu;
    }

    /*
        新增功能
     */
    @Override
    public Integer insert(Student stu) {
        Integer result = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try{
            //1.加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");

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

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

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

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //6.返回结果
        return result;
    }

    /*
        修改功能
     */
    @Override
    public Integer update(Student stu) {
        Integer result = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try{
            //1.加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");

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

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

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

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //6.返回结果
        return result;
    }

    /*
        删除功能
     */
    @Override
    public Integer delete(Integer id) {
        Integer result = null;
        SqlSession sqlSession = null;
        InputStream is = null;
        try{
            //1.加载核心配置文件
            is = Resources.getResourceAsStream("MyBatisConfig.xml");

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

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

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

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //5.释放资源
            if(sqlSession != null) {
                sqlSession.close();
            }
            if(is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //6.返回结果
        return result;
    }
}
5.2 LOG4J的配置和使用
  • 在日常开发过程中,排查问题时难免需要输出 MyBatis 真正执行的 SQL 语句、参数、结果等信息,我们就可以借助 LOG4J 的功能来实现执行信息的输出。

  • 使用步骤:

    1. 导入 jar 包:

      • log4j-1.2.17.jar
    2. 修改核心配置文件:MyBatisConfig.xml

      <!--配置LOG4J:以下name和value是固定写法-->
      <settings>
          <setting name="logImpl" value="log4j"/>
      </settings>
      
    3. 在 src 下编写 LOG4J 配置文件 : log4j.properties (配置文件名字也是固定写法)

      # Global logging configuration
      # 日志的四个级别,从高到低:ERROR(错误信息) WARN(警告信息) INFO(普通信息) DEBUG(调试信息,推荐使用)
      # stdout:输出到控制台
      log4j.rootLogger=DEBUG, stdout
      # 输出格式
      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

6.1 代理开发方式介绍
  • 采用 Mybatis 的代理开发方式实现 DAO 层的开发,这种方式是企业的主流。

  • Mapper 接口开发方法只需要程序员编写Mapper 接口(相当于Dao 接口),由Mybatis 框架根据接口定义创建接口的动态代理对象,代理对象的方法体同上边Dao接口实现类方法

  • 总结:接口代理方式,其实就我们自己不用实现MapperImpl(持久层实现类),mybatis通过接口代理的方式帮助我们实现

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

    1) Mapper.xml文件中的namespace与mapper接口的全限定名相同

    2) Mapper接口方法名和Mapper.xml中定义的每个statement的id相同

    3) Mapper接口方法的输入参数类型和mapper.xml中定义的每个sql的parameterType的类型相同

    4) Mapper接口方法的输出参数类型和mapper.xml中定义的每个sql的resultType的类型相同

6.2 代码实现
  • 实现步骤:
  1. 删除 mapper 层接口的实现类

  2. 修改映射配置文件

    <!-- 将命名空间修改为StudentMapper全路径名-->
    <mapper namespace="com.lichee.mapper.StudentMapper">
    
  3. 修改 service 层接口的实现类,采用接口代理方式实现功能(因为现在没有持久层实现类了,所以业务层无法直接调用,需要自己实现并且调用代理接口方式的MapperImpl)

    /*
        业务层实现类
     */
    public class StudentServiceImpl implements StudentService {
    
        @Override
        public List<Student> selectAll() {
            List<Student> list = null;
            SqlSession sqlSession = null;
            InputStream is = null;
            try{
                //1.加载核心配置文件
                is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
                //2.获取SqlSession工厂对象
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
                //3.通过工厂对象获取SqlSession对象
                sqlSession = sqlSessionFactory.openSession(true);
    
                //4.获取StudentMapper接口的实现类对象
                StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();
    
                //5.通过实现类对象调用方法,接收结果
                list = mapper.selectAll();
    
            } catch (Exception e) {
    
            } finally {
                //6.释放资源
                if(sqlSession != null) {
                    sqlSession.close();
                }
                if(is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            //7.返回结果
            return list;
        }
    
        @Override
        public Student selectById(Integer id) {
            Student stu = null;
            SqlSession sqlSession = null;
            InputStream is = null;
            try{
                //1.加载核心配置文件
                is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
                //2.获取SqlSession工厂对象
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
                //3.通过工厂对象获取SqlSession对象
                sqlSession = sqlSessionFactory.openSession(true);
    
                //4.获取StudentMapper接口的实现类对象
                StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();
    
                //5.通过实现类对象调用方法,接收结果
                stu = mapper.selectById(id);
    
            } catch (Exception e) {
    
            } finally {
                //6.释放资源
                if(sqlSession != null) {
                    sqlSession.close();
                }
                if(is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            //7.返回结果
            return stu;
        }
    
        @Override
        public Integer insert(Student stu) {
            Integer result = null;
            SqlSession sqlSession = null;
            InputStream is = null;
            try{
                //1.加载核心配置文件
                is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
                //2.获取SqlSession工厂对象
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
                //3.通过工厂对象获取SqlSession对象
                sqlSession = sqlSessionFactory.openSession(true);
    
                //4.获取StudentMapper接口的实现类对象
                StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();
    
                //5.通过实现类对象调用方法,接收结果
                result = mapper.insert(stu);
    
            } catch (Exception e) {
    
            } finally {
                //6.释放资源
                if(sqlSession != null) {
                    sqlSession.close();
                }
                if(is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            //7.返回结果
            return result;
        }
    
        @Override
        public Integer update(Student stu) {
            Integer result = null;
            SqlSession sqlSession = null;
            InputStream is = null;
            try{
                //1.加载核心配置文件
                is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
                //2.获取SqlSession工厂对象
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
                //3.通过工厂对象获取SqlSession对象
                sqlSession = sqlSessionFactory.openSession(true);
    
                //4.获取StudentMapper接口的实现类对象
                StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();
    
                //5.通过实现类对象调用方法,接收结果
                result = mapper.update(stu);
    
            } catch (Exception e) {
    
            } finally {
                //6.释放资源
                if(sqlSession != null) {
                    sqlSession.close();
                }
                if(is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            //7.返回结果
            return result;
        }
    
        @Override
        public Integer delete(Integer id) {
            Integer result = null;
            SqlSession sqlSession = null;
            InputStream is = null;
            try{
                //1.加载核心配置文件
                is = Resources.getResourceAsStream("MyBatisConfig.xml");
    
                //2.获取SqlSession工厂对象
                SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
    
                //3.通过工厂对象获取SqlSession对象
                sqlSession = sqlSessionFactory.openSession(true);
    
                //4.获取StudentMapper接口的实现类对象
                StudentMapper mapper = sqlSession.getMapper(StudentMapper.class); // StudentMapper mapper = new StudentMapperImpl();
    
                //5.通过实现类对象调用方法,接收结果
                result = mapper.delete(id);
    
            } catch (Exception e) {
    
            } finally {
                //6.释放资源
                if(sqlSession != null) {
                    sqlSession.close();
                }
                if(is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            //7.返回结果
            return result;
        }
    }
    
  • 最后测试:通过StudentController的测试类来直接测试,能够测试通过即可
6.3 源码分析
  • 分析动态代理对象如何生成的?

    • 通过动态代理开发模式,我们只编写一个接口,不写实现类,我们通过 getMapper() 方法最终获取到 org.apache.ibatis.binding.MapperProxy 代理对象,然后执行功能,

    • 而这个代理对象正是 MyBatis 使用了 JDK 的动态代理技术,帮助我们生成了代理实现类对象。从而可以进行相关持久化操作。

    • 跟踪getMapper方法,最终可以跟踪到如下代码:这个代码就是我们之前自己实现动态代理的代码:

  • 分析方法是如何执行的?

    • 分析过程:

      • 跟踪mapper.insert方法,代码打断点,然后调试跟踪

      • 代码执行到insert之后,进入方法的执行,然后就进入到了invoke方法(动态代理执行方法,都会执行invoke)

      • 在invoke中调用了mapperMethod.execute()方法

      • 这个方法中通过 switch 语句根据操作类型来判断是新增、修改、删除、查询操作,

      • 最后一步回到了 MyBatis 最原生的 SqlSession 方式来执行增删改查

6.4 知识小结
  • 接口代理方式可以让我们只编写接口即可,而实现类对象由 MyBatis 生成

  • 实现规则 :

    1. 映射配置文件中的名称空间必须和 Dao 层接口的全类名相同
    2. 映射配置文件中的增删改查标签的 id 属性必须和 Dao 层接口的方法名相同
    3. 映射配置文件中的增删改查标签的 parameterType 属性必须和 Dao 层接口方法的参数相同
    4. 映射配置文件中的增删改查标签的 resultType 属性必须和 Dao 层接口方法的返回值相同
  • 获取动态代理对象

    • 获取动态代理对象 SqlSession 功能类中的 getMapper() 方法

七. 动态sql语句

7.1 动态sql语句概述
  • Mybatis 的映射文件中,前面我们的 SQL 都是比较简单的,

  • 有些时候业务逻辑复杂时,我们的 SQL是动态变化的,此时在前面的学习中我们的 SQL 就不能满足要求了。

  • 代码:

    1. StudentMapper.xml增加多条件sql

      <select id="selectCondition" resultType="student" parameterType="student">
          select * from student where id=#{id} and name = #{name} and age = #{age}
      </select>
      
    2. Mapper接口:增加多条件查询方法

      //多条件查询
      public abstract List<Student> selectCondition(Student stu);
      
    3. 测试类:

      @Test
      public void selectCondition() throws Exception{
          InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
          SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
          SqlSession sqlSession = sqlSessionFactory.openSession(true);
          //获取StudentMapper接口的实现类对象
          StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
      
          Student stu = new Student();
          stu.setId(2);
          stu.setName("李四");
          stu.setAge(24);   
          //调用实现类的方法,接收结果
          List<Student> list = mapper.selectCondition(stu);
      
          //处理结果
          for (Student student : list) {
              System.out.println(student);
          }
      
          sqlSession.close();
          is.close();
      }
      
    4. 3个条件结果正常。2个条件(将setAge屏蔽掉)结果:如果有一个参数没有传递,默认是null,这肯定查询不到数据

7.2 动态 SQL 之<if>
  • 我们根据实体类的不同取值,使用不同的 SQL语句来进行查询。

  • 比如在 id如果不为空时可以根据id查询,如果username 不同空时还要加入用户名作为条件。

  • 这种情况在我们的多条件组合查询中经常会碰到。

  • 我们需要动态sql标签where和if。

  • <where>:条件标签,如果有动态条件,则使用该标签代替where关键字

  • <if>:条件判断标签

    <if test="条件判断">
    	拼接的查询条件
    </if>
    
  • 如下图:

    <select id="selectCondition" resultType="student" parameterType="student">
        select * from student
        <where>
            <if test="id != null">
                id = #{id}
            </if>
            <if test="name != null">
                AND name = #{name} <!--如果没有传递id,会不会直接是where and name=xxx,不会,mybatis会做特殊处理-->
            </if>
            <if test="age != null">
                AND age = #{age}
            </if>
        </where>
    </select>
    
  • 总结语法:

    <where>:条件标签。如果有动态条件,则使用该标签代替 where 关键字。
    <if>:条件判断标签。语法如下:
    <if test=“条件判断”>
    	拼接的查询条件
    </if>
    
7.3 动态 SQL 之<foreach>
  • <foreach>:循环遍历标签。适用于多个参数或者的关系

    <foreach collection="" open="" close="" item="" separator="">
    	获取参数
    </foreach>
    
  • 属性

    • collection:参数容器类型,(list-集合,array-数组)
    • open:开始的SQL语句
    • close:结束的SQL语句
    • item:参数变量名
    • separator:分隔符
  • 增加映射配置:

    <select id="selectByIds" resultType="student" parameterType="list">
        <include refid="select"/>
        <where>
            <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
    
  • 增加接口:

    //根据多个id查询
    public abstract List<Student> selectByIds(List<Integer> ids);
    
  • Test01中增加测试方法:

    @Test
    public void selectByIds() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        //获取StudentMapper接口的实现类对象
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
    
        //调用实现类的方法,接收结果
        List<Student> list = mapper.selectByIds(ids);
    
        for (Student student : list) {
            System.out.println(student);
        }
    
        sqlSession.close();
        is.close();
    }
    
  • 测试:给ids集合中增加1和2测试,然后再集合中增加3来测试,发现都可以

7.4 SQL片段抽取
  • 我们发现在映射文件中的sql语句,有很多都有重复的部分,可以通过sql片段抽取:

  • Sql 中可将重复的 sql 提取出来,使用时用 include 引用即可,最终达到 sql 重用的目的

  • 映射文件:

<mapper namespace="com.lichee.mapper.StudentMapper">
	<!--抽取-->
    <sql id="select" >SELECT * FROM student</sql>
    <select id="selectAll" resultType="student">
        <!--引用-->
        <include refid="select"/>
    </select>

    <select id="selectById" resultType="student" parameterType="int">
        <!--引用-->
        <include refid="select"/> WHERE id = #{id}
    </select>

    <insert id="insert" parameterType="student">
        INSERT INTO student VALUES (#{id},#{name},#{age})
    </insert>

    <update id="update" parameterType="student">
        UPDATE student SET name = #{name},age = #{age} WHERE id = #{id}
    </update>

    <delete id="delete" parameterType="int">
        DELETE FROM student WHERE id = #{id}
    </delete>

    <select id="selectCondition" resultType="student" parameterType="student">
        <!--引用-->
        <include refid="select"/>
        <where>
            <if test="id != null">
                id = #{id}
            </if>
            <if test="name != null">
                AND name = #{name}
            </if>
            <if test="age != null">
                AND age = #{age}
            </if>
        </where>
    </select>

    <select id="selectByIds" resultType="student" parameterType="list">
        <!--引用-->
        <include refid="select"/>
        <where>
            <foreach collection="list" open="id IN (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </where>
    </select>
</mapper>
7.5 知识小结
  • 动态SQL指的就是SQL语句可以根据条件或者参数的不同进行动态的变化。
  • <where>:条件标签。
  • <if>:条件判断的标签。
  • <foreach>:循环遍历的标签。
  • <sql>:抽取SQL片段的标签。
  • <include>:引入SQL片段的标签。

八. 分页插件

8.1 分页插件介绍
  • 分页可以将很多条结果进行分页显示
  • 如果当前在第一页,则没有上一页。如果当前在最后一页,则没有下一页
  • 需要明确当前是第几页,这一页中显示多少条结果
  • MyBatis分页插件总结
    • 在企业级开发中,分页也是一种常见的技术
    • 而目前使用的 MyBatis 是不带分页功能的,如果想实现分页的功能,需要我们手动编写 LIMIT 语句
    • 但是不同的数据库实现分页的 SQL 语句也是不同的,所以手写分页成本较高
    • 这个时候就可以借助分页插件来帮助我们实现分页功能
    • PageHelper:第三方分页助手。将复杂的分页操作进行封装,从而让分页功能变得非常简单
8.2 分页插件的使用
  • MyBatis可以使用第三方的插件来对功能进行扩展,分页助手PageHelper是将分页的复杂操作进行封装,使用简单的方式即可获得分页的相关数据

  • 开发步骤:

  • ①导入与PageHelper的jar包

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

<!-- 注意:分页助手的插件  配置在通用mapper之前 。 interceptor:拦截器,插件都是以拦截器形式实现的 -->
<plugin interceptor="com.github.pagehelper.PageHelper">
    <!-- 指定方言 -->
    <property name="dialect" value="mysql"/>
    <!-- 其实就是指定到底是哪种sql语句,每种数据库的sql语句都有些许区别,所以可以理解为都有自己的方言-->
</plugin>
  • ③测试:
public class Test01 {
    @Test
    public void selectPaging() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        //通过分页助手来实现分页功能 startPage参数1:当前页码,参数2:每页显示几条
        // 第一页:显示3条数据  pageNum,pageSize
        //PageHelper.startPage(1,3);
        // 第二页:显示3条数据
        //PageHelper.startPage(2,3);
        // 第三页:显示3条数据
        PageHelper.startPage(3,3);

        //调用实现类的方法,接收结果
        List<Student> list = mapper.selectAll();
        for (Student student : list) {
            System.out.println(student);
        }

        sqlSession.close();
        is.close();
    }
}
8.3 分页插件的参数获取
  • PageInfo:封装分页相关参数的功能类

  • 核心方法:

    返回值方法名说明
    longgetTotal()获取总条数
    intgetPages()获取总页数
    intgetPageNum()获取当前页
    intgetPageSize()获取每页显示条数
    intgetPrePage()获取上一页
    intgetNextPage()获取下一页
    booleanisIsFirstPage()获取是否是第一页
    booleanisIsLastPage()获取是否是最后一页
  • 测试:修改Test01代码,在释放资源之前,增加如下代码:

    //其他分页的数据
    PageInfo<User> pageInfo = new PageInfo<User>(select);
    System.out.println("总条数:"+pageInfo.getTotal());
    System.out.println("总页数:"+pageInfo.getPages());
    System.out.println("当前页:"+pageInfo.getPageNum());
    System.out.println("每页显示长度:"+pageInfo.getPageSize());
    System.out.println("是否第一页:"+pageInfo.isIsFirstPage());
    System.out.println("是否最后一页:"+pageInfo.isIsLastPage());
    
8.4 分页插件知识小结
  • 分页:可以将很多条结果进行分页显示
  • 分页插件 jar 包: pagehelper-5.1.10.jar 、 jsqlparser-3.1.jar

  • <plugins>:集成插件标签

  • 分页助手相关 API

    • PageHelper:分页助手功能类:
      1. startPage():设置分页参数
    • PageInfo:分页相关参数功能类:
      1. getTotal():获取总条数
      2. getPages():获取总页数
      3. getPageNum():获取当前页
      4. getPageSize():获取每页显示条数
      5. getPrePage():获取上一页
      6. getNextPage():获取下一页
      7. isIsFirstPage():获取是否是第一页
      8. isIsLastPage():获取是否是最后一页

九.MyBatis的多表操作

9.1 多表模型介绍
  • 多表模型分类

    • 一对一:在任意一方建立外键,关联对方的主键
    • 一对多:在多的一方建立外键,关联一的一方的主键
    • 多对多:借助中间表,中间表至少两个字段,分别关联两张表的主键
9.2 多表模型一对一操作
  • 一对一模型: 人和身份证,一个人只有一个身份证

  • 代码实现

  • sql语句准备

    CREATE TABLE person(
        id INT PRIMARY KEY AUTO_INCREMENT,
        NAME VARCHAR(20),
        age INT
    );
    INSERT INTO person VALUES (NULL,'张三',23);
    INSERT INTO person VALUES (NULL,'李四',24);
    INSERT INTO person VALUES (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);
    INSERT INTO card VALUES (NULL,'23456',2);
    INSERT INTO card VALUES (NULL,'34567',3);
    
    • jdbc.properties

      driver=com.mysql.jdbc.Driver
      url=jdbc:mysql://127.0.0.1:3306/db2
      username=root
      password=root
      
    • MyBatisConfig.xml

      <?xml version="1.0" encoding="UTF-8" ?>
      <!--MyBatis的DTD约束-->
      <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
      
      <!--configuration 核心根标签-->
      <configuration>
      
          <!--引入数据库连接的配置文件-->
          <properties resource="jdbc.properties"/>
      
          <!--配置LOG4J-->
          <settings>
              <setting name="logImpl" value="log4j"/>
          </settings>
      
          <!--起别名-->
          <typeAliases>
              <package name="com.lichee.bean"/>
          </typeAliases>
      
          <!--environments配置数据库环境,环境可以有多个。default属性指定使用的是哪个-->
          <environments default="mysql">
              <!--environment配置数据库环境  id属性唯一标识-->
              <environment id="mysql">
                  <!-- transactionManager事务管理。  type属性,采用JDBC默认的事务-->
                  <transactionManager type="JDBC"></transactionManager>
                  <!-- dataSource数据源信息   type属性 连接池-->
                  <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引入映射配置文件 -->
          <mappers>
          </mappers>
      </configuration>
      
    • log4j.properties

      # 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
      
  • javabean:Card

    public class Card {
        private Integer id;     //主键id
        private String number;  //身份证号
    
        private Person p;       //所属人的对象	在表中是外键pid:人id,但是在javabean中一般都是外键对应的实体类javabean
    
        //Constructor
        //Getter and Setter
        //toString
    }
    
  • javabean:Person

    public class Person {
        private Integer id;     //主键id
        private String name;    //人的姓名
        private Integer age;    //人的年龄
    
        //Constructor
        //Getter and Setter
        //toString
    }
    
  • 配置文件:新建com.lichee.one_to_one.OneToOneMapper.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.lichee.table01.OneToOneMapper">
        <!--配置字段和实体对象属性的映射关系
    	type指定要配置的实体对象是哪个:card
    	-->
        <resultMap id="oneToOne" type="card">
            <!--id配置主键列:将sql中查询的cid列与card实体类中的id进行关联 -->
            <id column="cid" property="id" />
            <!--result配置非主键列-->
            <result column="number" property="number" />
            <!--
                association:配置被包含对象的映射关系
                property:被包含对象的变量名(属性名,在Card实体类中有一个p属性)
                javaType:被包含对象的数据类型(直接给person别名,因为我们通过typeAliases统一设置了bean包下所有实体类的别名了)
            -->
            <association property="p" javaType="person">
                <id column="pid" property="id" />
                <result column="name" property="name" />
                <result column="age" property="age" />
            </association>
        </resultMap>
    	<!--resultMap属性指定的是resultMap标签的id
    	查询出来的结果涉及到两张表,所以不能使用resultType了
    	-->
        <select id="selectAll" resultMap="oneToOne">
            SELECT c.id cid,number,pid,NAME,age FROM card c,person p WHERE c.pid=p.id
        </select>
    </mapper>
    
  • MyBatisConfig.xml中配置映射文件:

    <mappers>
        <mapper resource="com/lichee/one_to_one/OneToOneMapper.xml"/>
    </mappers>
    
  • 接口:com.lichee.table01.OneToOneMapper

    public interface OneToOneMapper {
        //查询全部
        public abstract List<Card> selectAll();
    }
    
    1. 测试类:
    public class Test01 {
      @Test
      public void selectAll() throws Exception{
          InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
          SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
          SqlSession sqlSession = sqlSessionFactory.openSession(true);
          OneToOneMapper mapper = sqlSession.getMapper(OneToOneMapper.class);
    
          List<Card> list = mapper.selectAll();
          for (Card c : list) {
              System.out.println(c);
          }
    
          sqlSession.close();
          is.close();
      }
    }
    
  • 一对一配置总结:

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:唯一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<association>:配置被包含对象的映射关系标签。
    property 属性:被包含对象的变量名
    javaType 属性:被包含对象的数据类型
9.3 多表模型一对多操作
  • 一对多模型: 一对多模型:班级和学生,一个班级可以有多个学生

  • 代码实现

    1. sql语句准备
    CREATE TABLE classes(
      id INT PRIMARY KEY AUTO_INCREMENT,
      NAME VARCHAR(20)
    );
    INSERT INTO classes VALUES (NULL,'黑马一班');
    INSERT INTO classes VALUES (NULL,'黑马二班');
    
    CREATE TABLE student(
      id INT PRIMARY KEY AUTO_INCREMENT,
      NAME VARCHAR(30),
      age INT,
      cid INT,
      CONSTRAINT cs_fk FOREIGN KEY (cid) REFERENCES classes(id)
    );
    INSERT INTO student VALUES (NULL,'张三',23,1);
    INSERT INTO student VALUES (NULL,'李四',24,1);
    INSERT INTO student VALUES (NULL,'王五',25,2);
    INSERT INTO student VALUES (NULL,'赵六',26,2);
    
    1. 新建javabean:Classes
    public class Classes {
      private Integer id;     //主键id
      private String name;    //班级名称
    
      private List<Student> students; //班级中所有学生对象		一个班级里多个学生
    
      //Constructor
      //Getter and Setter
      //toString
    }
    
    1. javabean:Student
    public class Student {
      private Integer id;     //主键id
      private String name;    //学生姓名
      private Integer age;    //学生年龄
    
      //Constructor
      //Getter and Setter
      //toString
    }
    
    1. 配置文件:com.lichee.one_to_many.OneToManyMapper.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.lichee.table02.OneToManyMapper">
        <resultMap id="oneToMany" type="classes">
            <id column="cid" property="id"/>
            <result column="cname" property="name"/>
    
            <!--
                collection:配置被包含的集合对象映射关系(如果被包含的对象是多的一方,需要用collection)
                property:被包含对象的变量名
                ofType:被包含对象的实际数据类型(collection标签中指定被包含对象类型用的是ofType)
            -->
            <collection property="students" ofType="student">
                <id column="sid" property="id"/>
                <result column="sname" property="name"/>
                <result column="sage" property="age"/>
            </collection>
        </resultMap>
        <select id="selectAll" resultMap="oneToMany">
            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
        </select>
    </mapper>
    
    1. 配置映射文件
    <mappers>
      <mapper resource="com/lichee/one_to_one/OneToOneMapper.xml"/>
      <mapper resource="com/lichee/one_to_many/OneToManyMapper.xml"/>
    </mappers>
    
    1. 接口
    public interface OneToManyMapper {
      //查询全部
      public abstract List<Classes> selectAll();
    }
    
    1. 测试类com.lichee.table02.Test01
    public class Test01 {
      @Test
      public void selectAll() throws Exception{
          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> classes = mapper.selectAll();
          for (Classes cls : classes) {
              System.out.println(cls.getId() + "," + cls.getName());
              List<Student> students = cls.getStudents();
              for (Student student : students) {
                  System.out.println("\t" + student);
              }
          }
    
          sqlSession.close();
          is.close();
      }
    }
    
  • 一对多配置文件总结:

<resultMap>:配置字段和对象属性的映射关系标签。
    id 属性:唯一标识
    type 属性:实体对象类型
<id>:配置主键映射关系标签。
<result>:配置非主键映射关系标签。
    column 属性:表中字段名称
    property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
    property 属性:被包含集合对象的变量名
    ofType 属性:集合中保存的对象数据类型
9.4 多表模型多对多操作
  • 多对多模型:学生和课程,一个学生可以选择多门课程、一个课程也可以被多个学生所选择

  • 代码实现

    1. sql语句准备
    CREATE TABLE course(
      id INT PRIMARY KEY AUTO_INCREMENT,
      NAME VARCHAR(20)
    );
    INSERT INTO course VALUES (NULL,'语文');
    INSERT INTO course VALUES (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);
    INSERT INTO stu_cr VALUES (NULL,1,2);
    INSERT INTO stu_cr VALUES (NULL,2,1);
    INSERT INTO stu_cr VALUES (NULL,2,2);
    
    1. Javabean
    public class Course {
      private Integer id;     //主键id
      private String name;    //课程名称
    
      //Constructor
      //Getter and Setter
      //toString
    }
    
    1. 修改:Student
    private List<Course> courses;   // 学生所选择的课程集合
    
    public Student(Integer id, String name, Integer age, List<Course> courses) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.courses = courses;
    }
    public List<Course> getCourses() {
        return courses;
    }
    
    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }
    
    1. 我们这里只是多表查询,不做其他操作,所以中间表不需要对应的实体类

    2. 配置文件

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE mapper
              PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
              "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.lichee.table03.ManyToManyMapper">
        <resultMap id="manyToMany" type="student">
            <id column="sid" property="id"/>
            <result column="sname" property="name"/>
            <result column="sage" property="age"/>
    
            <collection property="courses" ofType="course">
                <id column="cid" property="id"/>
                <result column="cname" property="name"/>
            </collection>
        </resultMap>
        <select id="selectAll" resultMap="manyToMany">
            SELECT sc.sid,s.name sname,s.age sage,sc.cid,c.name cname FROM student s,course c,stu_cr sc WHERE sc.sid=s.id AND sc.cid=c.id
        </select>
        <!--注意这里查询的是sc.cid,将这个cid给course的id了,这也是可以的,因为都是课程id
        但其实sql语句中的sc.cid,可以换成c.id,这样的话给course的id更合适	
       -->
    </mapper>
    
    1. 配置
    <mappers>
        <mapper resource="com/lichee/one_to_one/OneToOneMapper.xml"/>
        <mapper resource="com/lichee/one_to_many/OneToManyMapper.xml"/>
        <mapper resource="com/lichee/many_to_many/ManyToManyMapper.xml"/>
    </mappers>
    
    1. 接口
    public interface ManyToManyMapper {
        //查询全部
        public abstract List<Student> selectAll();
    }
    
    1. 测试类
    public class Test01 {
        @Test
        public void selectAll() throws Exception{
            InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
            SqlSession sqlSession = sqlSessionFactory.openSession(true);
            ManyToManyMapper mapper = sqlSession.getMapper(ManyToManyMapper.class);
    
            List<Student> students = mapper.selectAll();
            for (Student student : students) {
                System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
                List<Course> courses = student.getCourses();
                for (Course cours : courses) {
                    System.out.println("\t" + cours);
                }
            }
    
            sqlSession.close();
            is.close();
        }
    }
    
  • 多对多配置文件总结:

<resultMap>:配置字段和对象属性的映射关系标签。
	id 属性:唯一标识
	type 属性:实体对象类型
 <id>:配置主键映射关系标签。
 <result>:配置非主键映射关系标签。
	column 属性:表中字段名称
	property 属性: 实体对象变量名称
<collection>:配置被包含集合对象的映射关系标签。
	property 属性:被包含集合对象的变量名
	ofType 属性:集合中保存的对象数据类型
9.5 多表模型操作总结
  • 多表模型分析:一对一、一对多、多对多。
  • <resultMap>:配置字段和对象属性的映射关系标签。
    • id属性:唯一标识
    • type属性:实体对象类型
  • <id>:配置主键映射关系标签。
  • <result>:配置非主键映射关系标签
    • column属性:表中字段名称
    • property属性:实体对象变量名称
  • <association>:配置被包含对象的映射关系标签。
    • property属性:被包含对象变量名称
    • javaType属性:被包含对象的数据类型
  • <collection>:配置被包含集合对象的映射关系映射。
    • property属性:被包含集合对象变量名称
    • ofType属性:集合中保存的对象数据类型

十.Mybatis注解开发单表操作

10.1 MyBatis的常用注解
  • 常用注解

    • @Select(“查询的 SQL 语句”):执行查询操作注解

    • @Insert(“查询的 SQL 语句”):执行新增操作注解

    • @Update(“查询的 SQL 语句”):执行修改操作注解

    • @Delete(“查询的 SQL 语句”):执行删除操作注解

10.2 注解实现查询操作
  1. javabean

    public class Student {
        private Integer id;
        private String name;
        private Integer age;
    
        //Constructor
        //Getter and Setter
        //toString
    }
    
  2. 创建mapper接口

    public interface StudentMapper {
        //查询全部
        @Select("SELECT * FROM student")
        public abstract List<Student> selectAll();
    }
    
  3. 配置MyBatisConfig.xml

    <!--配置映射关系:这里已经没有Mapper映射文件了,但是我们需要配置mapper接口所在的包-->
    <mappers>
        <package name="com.lichee.mapper"/>
    </mappers>
    <!--其实是注解的方式帮助我们生成了映射文件,所以我们依然是在mappers节点里配置-->
    
  4. 测试类:

    @Test
    public void selectAll() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    
        List<Student> list = mapper.selectAll();
        for (Student student : list) {
            System.out.println(student);
        }
        
        sqlSession.close();
        is.close();
    }
    
  • 注意:

    • 修改MyBatis的核心配置文件,我们使用了注解替代的映射文件,所以我们只需要加载使用了注解的Mapper接口即可
    <mappers>
        <!--扫描使用注解的类-->
        <mapper class="com.lichee.mapper.UserMapper"></mapper>
    </mappers>
    
    • 或者指定扫描包含映射关系的接口所在的包也可以
    <mappers>
        <!--扫描使用注解的类所在的包-->
        <package name="com.lichee.mapper"></package>
    </mappers>
    
10.3 注解实现新增操作
  1. StudentMapper新增接口方法

    //新增操作: sql的参数与之前的写法一致,从insert方法的参数中获取对应属性值
    @Insert("INSERT INTO student VALUES (#{id},#{name},#{age})")
    public abstract Integer insert(Student stu);
    
  2. 测试方法

    @Test
    public void insert() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    
        Student stu = new Student(4,"赵六",26);
        Integer result = mapper.insert(stu);
        System.out.println(result);
    
        sqlSession.close();
        is.close();
    }
    
10.4 注解实现修改操作
  1. StudentMapper新增接口方法

    //修改操作
    @Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}")
    public abstract Integer update(Student stu);
    
  2. 测试方法

    @Test
    public void update() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    
        Student stu = new Student(4,"赵六",36);
        Integer result = mapper.update(stu);
        System.out.println(result);
    
        sqlSession.close();
        is.close();
    }
    
10.5 注解实现删除操作
  1. StudentMapper新增接口方法

    //删除操作
    @Delete("DELETE FROM student WHERE id=#{id}")
    public abstract Integer delete(Integer id);
    
  2. 测试方法

    @Test
    public void delete() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
    
        Integer result = mapper.delete(4);
        System.out.println(result);
    
        sqlSession.close();
        is.close();
    }
    
10.6 注解开发总结

注解可以简化开发操作,省略映射配置文件的编写

  • 常用注解

    @Select(“查询的 SQL 语句”):执行查询操作注解

    @Insert(“查询的 SQL 语句”):执行新增操作注解

    @Update(“查询的 SQL 语句”):执行修改操作注解

    @Delete(“查询的 SQL 语句”):执行删除操作注解

  • 配置映射关系

    <mappers> <package name="接口所在包"/> </mappers>    
    

十一.MyBatis注解开发的多表操作

11.1 MyBatis的注解实现复杂映射开发
  • 实现复杂关系映射之前我们可以在映射文件中通过配置<resultMap>来实现,

  • 使用注解开发后,我们可以使用@Results注解,@Result注解,@One注解,@Many注解组合完成复杂关系的配置

    注解说明
    @Results代替的是标签<resultMap>该注解中可以使用单个@Result注解,也可以使用@Result集合。
    使用格式:@Results ({@Result () ,@Result()})或@Results (@Result () )
    @Result代替了<id>标签和<result>标签
    @Result中属性介绍:
    column:数据库的列名
    property:需要装配的属性名
    one:需要使用的@One注解(@Result (one=@One) ( ) ) )
    many:需要使用的@Many注解(@Result (many=@many) ( ) ) )
    @One(一对一)代替了<assocation>标签,是多表查询的关键,在注解中用来指定子查询返回单一对象。
    @One注解属性介绍:
    select:指定用来多表查询的 sqlmapper
    使用格式:@Result(column=" “,property=”",one=@One(select=""))
    @Many(多对一)代替了<collection>标签,是是多表查询的关键,在注解中用来指定子查询返回对象集合。
    使用格式:@Result(property="",column="",many=@Many(select=""))
11.2 一对一查询
11.2.0 准备工作
  1. javabean - card

    public class Card {
        private Integer id;     //主键id
        private String number;  //身份证号
    
        private Person p;       //所属人的对象
    
        //Constructor
        //Getter and Setter
        //toString
    }
    
  2. javabean - person

    public class Person {
        private Integer id;     //主键id
        private String name;    //人的姓名
        private Integer age;    //人的年龄
    
        //Constructor
        //Getter and Setter
        //toString
    }
    
  3. cardMapper接口:我们的核心就是要在Card中做一些处理,实现一对一的查询

    public interface CardMapper {
        //查询全部
        public abstract List<Card> selectAll();
    }
    
11.2.1 一对一查询的模型

一对一查询的需求:查询一个用户信息,与此同时查询出该用户对应的身份证信息

11.2.2 一对一查询的语句

对应的sql语句:

SELECT * FROM card; -- 只根据这个sql语句只能查询出来card的数据

SELECT * FROM person WHERE id=#{id}; -- 需要根据card表中查询出来的pid,再次查询person数据才能将person数据也查询出来
11.2.3 创建PersonMapper接口
public interface PersonMapper {
    //根据id查询
    @Select("SELECT * FROM person WHERE id=#{id}")
    public abstract Person selectById(Integer id);
}
11.2.4 使用注解配置CardMapper
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.lichee.one_to_one.PersonMapper.selectById")
            )
    })
    public abstract List<Card> selectAll();
}
2.2.5 测试类
public class Test01 {
    @Test
    public void selectAll() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        CardMapper mapper = sqlSession.getMapper(CardMapper.class);

        List<Card> list = mapper.selectAll();
        for (Card card : list) {
            System.out.println(card);
        }

        sqlSession.close();
        is.close();
    }
}
11.2.6 一对一配置总结
@Results:封装映射关系的父注解。
	Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
	column 属性:查询出的表中字段名称
	property 属性:实体对象中的属性名称
	javaType 属性:被包含对象的数据类型
	one 属性:一对一查询固定属性
@One:一对一查询的注解。
	select 属性:指定调用某个接口中的方法
11.3 一对多查询
11.3.1 一对多查询的模型

一对多查询的需求:查询一个课程,与此同时查询出该该课程对应的学生信息

11.3.2 一对多查询的语句

对应的sql语句:

SELECT * FROM classes

SELECT * FROM student WHERE cid=#{cid}
11.3.3 创建StudentMapper接口
public interface StudentMapper {
    //根据cid查询student表
    @Select("SELECT * FROM student WHERE cid=#{cid}")
    public abstract List<Student> selectByCid(Integer cid);
}
11.3.4 使用注解配置Mapper
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.lichee.one_to_many.StudentMapper.selectByCid")
            )
    })
    public abstract List<Classes> selectAll();
}
11.3.5 测试类
public class Test01 {
    @Test
    public void selectAll() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        ClassesMapper mapper = sqlSession.getMapper(ClassesMapper.class);

        List<Classes> list = mapper.selectAll();
        for (Classes cls : list) {
            System.out.println(cls.getId() + "," + cls.getName());
            List<Student> students = cls.getStudents();
            for (Student student : students) {
                System.out.println("\t" + student);
            }
        }

        sqlSession.close();
        is.close();
    }
}
11.3.6 一对多配置总结
@Results:封装映射关系的父注解。
	Result[] value():定义了 Result 数组
@Result:封装映射关系的子注解。
	column 属性:查询出的表中字段名称
	property 属性:实体对象中的属性名称
	javaType 属性:被包含对象的数据类型
	many 属性:一对多查询固定属性
@Many:一对多查询的注解。
	select 属性:指定调用某个接口中的方法
11.4 多对多查询
11.4.1 多对多查询的模型

多对多查询的需求:查询学生以及所对应的课程信息

11.4.2 多对多查询的语句

对应的sql语句:

SELECT DISTINCT s.id,s.name,s.age FROM student s,stu_cr sc WHERE sc.sid=s.id
SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}
11.4.3 添加CourseMapper 接口方法
public interface CourseMapper {
    //根据学生id查询所选课程
    @Select("SELECT c.id,c.name FROM stu_cr sc,course c WHERE sc.cid=c.id AND sc.sid=#{id}")
    public abstract List<Course> selectBySid(Integer id);
}
11.4.4 使用注解配置Mapper
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.lichee.many_to_many.CourseMapper.selectBySid")
            )
    })
    public abstract List<Student> selectAll();
}

11.4.5 测试类
public class Test01 {
    @Test
    public void selectAll() throws Exception{
        InputStream is = Resources.getResourceAsStream("MyBatisConfig.xml");
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is);
        SqlSession sqlSession = sqlSessionFactory.openSession(true);
        StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);

        List<Student> list = mapper.selectAll();
        for (Student student : list) {
            System.out.println(student.getId() + "," + student.getName() + "," + student.getAge());
            List<Course> courses = student.getCourses();
            for (Course cours : courses) {
                System.out.println("\t" + cours);
            }
        }

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

十二.构建sql

12.1 SQL 构建对象介绍
  • 我们之前通过注解开发时,相关 SQL 语句都是自己直接拼写的。一些关键字写起来比较麻烦、而且容易出错。

  • MyBatis 给我们提供了 org.apache.ibatis.jdbc.SQL 功能类,专门用于构建 SQL 语句

    方法名说明
    SELECT(String.column)根据字段拼接查询语句
    FROM(String…table)根据表名拼接语句
    WHERE(String…condition)根据条件拼接语句
    INSERT_INTO(String table)根据表名拼接新增语句
    VALUES(String column,String values)根据字段和值拼接插入数据语句
    UPDATE(String table)根据表名拼接修改语句
    DELETE_FROM(String table)根据表名拼接删除语句
    … …… …
  • 新建测试类:

    public class SqlTest {
        public static void main(String[] args) {
            String sql = getSql();
            System.out.println(sql);
        }
    
        //定义方法,获取查询student表的sql语句
        public static String getSql() {
            String sql = "SELECT * FROM student";
            return sql;
        }
    }
    
    • 如果sql语句比较长,sql中的关键字较多时,就可能会写错
  • 修改代码:使用SQL类通过的方法来编写sql语句

    public class SqlTest {
        public static void main(String[] args) {
            String sql = getSql();
            System.out.println(sql);
        }
    
        public static String getSql() {
            String sql = new SQL(){//通过SQL类提供的方法来实现sql语句的编写
                {
                    SELECT("*");
                    FROM("student");
                }
            }.toString();
            return sql;
        }
    }
    
12.2 查询功能的实现
  • 定义功能类并提供获取查询的 SQL 语句的方法

    • 新建类:ReturnSql,定义获取sql语句的方法
    public class ReturnSql {
        //定义方法,返回查询的sql语句
        public String getSelectAll() {
            return new SQL() {
                {
                    SELECT("*");
                    FROM("student");
                }
            }.toString();
        }
    }
    
    • 之前是在Mapper接口中直接通过注解(@Select,@Insert等)来设置的sql

    • 现在有提供了sql语句的方法,通过@SelectProvider注解来获取

    • @SelectProvider:生成查询用的 SQL 语句注解(调用提供sql语句的方法,获取到查询的sql语句

    • type 属性:用于指定生成 SQL 语句功能的类对象

      • method 属性:用于指定类中要执行获取sql语句的方法 (指定方法名,不加小括号)
  • 修改StudentMapper

    //查询全部
    //@Select("SELECT * FROM student")
    //注意:method只是指定一个方法的名字,SelectProvider内部会自己调用
    @SelectProvider(type = ReturnSql.class , method = "getSelectAll")
    public abstract List<Student> selectAll();
    
  • 运行test包中的Test01的selectAll方法,能查询出数据即可

12.3 新增功能的实现
  • 定义功能类并提供获取新增的 SQL 语句的方法,在ReturnSql中增加如下方法:

    //定义方法,返回新增的sql语句
    public String getInsert(Student stu) {
        return new SQL() {
            {
                INSERT_INTO("student");
                INTO_VALUES("#{id},#{name},#{age}");
            }
        }.toString();
    }
    
  • @InsertProvider:生成新增用的 SQL 语句注解(调用提供sql语句的方法,获取到新增的sql语句

    • type 属性:生成 SQL 语句功能类对象

      • method 属性:指定调用方法
  • 修改StudentMapper

    //新增功能
    //@Insert("INSERT INTO student VALUES (#{id},#{name},#{age})")
    @InsertProvider(type = ReturnSql.class , method = "getInsert")
    public abstract Integer insert(Student stu);
    
  • 运行test包中的Test01的insert方法,能插入数据即可

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

    //定义方法,返回修改的sql语句
    public String getUpdate(Student stu) {
        return new SQL() {
            {
                UPDATE("student");
                SET("name=#{name}","age=#{age}");
                WHERE("id=#{id}");
            }
        }.toString();
    }
    
  • @UpdateProvider:生成修改用的 SQL 语句注解(调用提供sql语句的方法,获取到更新的sql语句

    • type 属性:生成 SQL 语句功能类对象

      • method 属性:指定调用方法
  • 修改StudentMapper

    //修改功能
    //@Update("UPDATE student SET name=#{name},age=#{age} WHERE id=#{id}")
    @UpdateProvider(type = ReturnSql.class , method = "getUpdate")
    public abstract Integer update(Student stu);
    
  • 运行test包中的Test01的update方法,能更新数据即可

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

    //定义方法,返回删除的sql语句
    public String getDelete(Integer id) {
        return new SQL() {
            {
                DELETE_FROM("student");
                WHERE("id=#{id}");
            }
        }.toString();
    }
    
  • @DeleteProvider:生成删除用的 SQL 语句注解(调用提供sql语句的方法,获取到删除的sql语句

    • type 属性:生成 SQL 语句功能类对象

      • method 属性:指定调用方法
  • 修改StudentMapper

    //删除功能
    //@Delete("DELETE FROM student WHERE id=#{id}")
    @DeleteProvider(type = ReturnSql.class , method = "getDelete")
    public abstract Integer delete(Integer id);
    
  • 运行test包中的Test01的delete方法,能删除数据即可

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值