MyBatis

本文深入解析MyBatis框架的概念、部署、开发步骤及其在JavaWeb开发中的应用。涵盖ORM映射、CRUD操作、动态SQL、缓存机制、分页插件、注解使用等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

框架介绍

  • 框架概念

框架,是软件的半成品,完成了软件开发过程中的通用性功能,从而简化了软件的开发步骤、提高开发效率

  • Java web开发常用框架
    • MyBatis 简化了数据持久化操作的步骤,ORM框架 (Hibernate、EJB3、Spring JDBC)
    • Spring 提供了对象创建、初始化及对象管理的功能,容器框架
    • SpringMVC 完成前端和代码的交互,MVC框架

MyBatis介绍

MyBatis 是一个ORM框架,用于实现数据的持久化操作

2.1 ORM

ORM (Object Relational Mapping) 对象关系映射 就是将一个Java对象映射到数据表中的一行记录

2.2 JDBC操作的缺点
  • 存在大量的冗余代码、步骤繁琐

  • 数据库连接、Statement对象等都需要手动创建

  • 查询的结构需要手动进行数据封装

  • SQL没有经过优化直接执行,效率较低

2.3 了解MyBatis

MyBatis是apache的一个开源项目,前身是iBatis

  • 2010年托管到google code,更名为MyBatis;2013年托管到GitHub
  • MyBatis是一个优秀的Java持久层框架,支持SQL自定义
  • MyBatis底层就是对JDBC的封装,几乎消除了所有的JDBC步骤,我们只需要关注SQL本身

MyBatis框架部署

框架部署,就是将框架引入到我们的项目中

3.1 创建Maven项目

可以是Java应用,也可以是web应用

3.2 添加依赖

因为MyBatis是基于JDBC的封装,因此操作数据库也需要数据库驱动依赖

<!-- MySQL数据库驱动jar -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

<!-- MyBatis依赖 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.4.6</version>
</dependency>
3.3 创建MyBatis配置文件
  • 在resources目录创建mybatis-config.xml

  • 完成数据库连接配置

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <environments default="mysql">
    
            <environment id="mysql">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
                    <property name="driver" value="com.mysql.jdbc.Driver"/>
                    <property name="url" value="jdbc:mysql://localhost:3306/myshop?characterEncoding=utf-8"/>
                    <property name="username" value="root"/>
                    <property name="password" value="admin123"/>
                </dataSource>
            </environment>
    
        </environments>
    
    </configuration>
    

MyBatis开发步骤

4.1 建表
create table books(
	book_id int primary key auto_increment,
	book_name varchar(100) not null,
	book_author varchar(20) not null,
	book_price decimal(6,2) not null
);
4.2 创建实体类

添加lombok依赖

<!--lombok-->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>

创建实体类

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Book {
    private int bookId;
    private String bookName;
    private String bookAuthor;
    private double bookPrice;
}
4.3 定义DAO接口

在DAO接口中定义操作的方法

public interface BookDAO {
    public int insertBook(Book book);
}
4.4 映射配置
  • 在resources目录下创建一个mappers目录
  • 在mappers目录下创建一个.xml文件(MyBatis映射文件)
  • 完成Mapper文件的配置
<?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">

<!--namespace = 所需实现的接口全限定名-->
<mapper namespace="com.qfedu.dao.BookDAO">

    <insert id="insertBook">
        insert into books(book_name,book_author,book_price)
        values(#{bookName},#{bookAuthor},#{bookPrice})
    </insert>
    
</mapper>
4.5 注册Mapper

将mapper文件配置到主配置文件(mybatis-config.xml)

在mybatis-config.xml文件中:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!--<environments default="mysql">...</environments>-->
    
    <mappers>
        <mapper resource="mappers/BookMapper.xml"/>
    </mappers>

</configuration>

单元测试

5.1 添加单元测试依赖
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
</dependency>
5.2 创建测试类
  1. 在test目录中创建与被测试类所在包同名的包
  2. 在创建的包中,创建测试类(测试类名 = 被测试类名+Test)
测试类如图:

在这里插入图片描述

5.3 创建测试方法

在测试类中创建测试方法:

  • 测试方法无参数无返回值
  • 测试方法名与被测方法名同名(也可以在被测试方法名前加上test)
  • 添加@Test注解
测试方法

在这里插入图片描述

5.4 测试规则
package com.qfedu.dao;
public class BookDAOTest {

    @Test
    public void testInsertBook() throws IOException {
        //1.创建被测试类的对象
        //a.获取配置文件的输入流对象
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");

        //b.通过SqlSessionFactoryBuilder加载配置文件,构建SqlSession工厂
        SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);

        //c.从SqlSession工厂获取SqlSession(sqlSession就相当于JDBC中的Connection)
        SqlSession sqlSession = factory.openSession();

        //d.从数据库连接(会话:SqlSession)中获取DAO对象
        BookDAO bookDAO = sqlSession.getMapper(BookDAO.class);

        //2.准备被测试方法所需的参数
        Book book = new Book(0, "Java", "二狗", 222.22);

        //3.使用被测试类的对象调用被测试方法,并获取返回值
        int i = bookDAO.insertBook(book);
		sqlSession.commit();
        
        //4.结果断言
        //assertEquals(1,i);
        System.out.println(i);
        
    }

}

MyBatis工具类封装

package com.qfedu.utils;

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;

public class MyBatisUtil {

    private static SqlSessionFactory factory;
    private static final ThreadLocal<SqlSession> local = new ThreadLocal<SqlSession>();

    static{
        try {
            InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
            factory = new SqlSessionFactoryBuilder().build(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取sqlSession对象
     * @return
     */
    public static SqlSession openSession(){
        SqlSession sqlSession = local.get();
        if(sqlSession == null){
            //默认sqlSession不自动提交
            sqlSession = factory.openSession();
            //设置sqlSession自动提交
            //sqlSession = factory.openSession(true);
            local.set(sqlSession);
        }
        return sqlSession;
    }

    /**
     * 提交
     */
    public static void commit(){
        SqlSession sqlSession = openSession();
        sqlSession.commit();
        closeSession();
    }

    /**
     * 回滚
     */
    public static void rollback(){
        SqlSession sqlSession = openSession();
        sqlSession.rollback();
        closeSession();
    }

    /**
     * 关闭sqlSession
     */
    public static  void closeSession(){
        SqlSession sqlSession = openSession();
        sqlSession.close();
        local.remove();
    }

    /**
     * 获取Mapper对象
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T extends Object> T getMapper(Class<T> clazz){
        T dao = openSession().getMapper(clazz);
        return dao;
    }

}

七、MyBatis的CRUD操作

  • DAO接口

    public interface BookDAO {
    
        public int insertBook(Book book);
    
        public int deleteBook(int bookId);
    
        public int updateBook(Book book);
    
        public Book getBook(int bookId);
    
        public List<Book> listBooks();
    
    }
    
  • Mapper配置

    <?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">
    
    <!--namespace = 所需实现的接口全限定名-->
    <mapper namespace="com.qfedu.dao.BookDAO">
    
        <!--    public int insertBook(Book book);-->
        <insert id="insertBook">
            insert into books(book_name,book_author,book_price)
            values(#{bookName},#{bookAuthor},#{bookPrice})
        </insert>
    
        <!--    public int deleteBook(int bookId);-->
        <delete id="deleteBook">
            delete from books where book_id=#{bookId}
        </delete>
    
        <!--    public int updateBook(Book book);-->
        <update id="updateBook">
            update books set book_name=#{bookName}, 
            book_author=#{bookAuthor}, book_price=#{bookPrice}
            where book_id=#{bookId}
        </update>
    
        <!--    public Book getBook(int bookId);-->
        <select id="getBook" resultType="com.qfedu.pojo.Book">
            select book_id as bookId,book_name as bookName,
            book_author as bookAuthor,book_price as bookPrice
            from books where book_id=#{bookId}
        </select>
    
        <!--    public List<Book> listBooks();-->
        <select id="listBooks" resultSets="java.util.List" resultType="com.qfedu.pojo.Book">
            select book_id as bookId,book_name as bookName,
            book_author as bookAuthor,book_price as bookPrice
            from books
        </select>
    
    </mapper>
    

八、MyBatis配置文件

8.1 MyBatis核心配置文件

mybatis-config.xml 主要用于配置MyBatis的连接信息

properties 用于键值对定义
  • 在resources中创建mysql.properties,配置如下

    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/db_bims?characterEncoding=utf-8
    jdbc.username=root
    jdbc.password=admin123
    
  • 在mybatis-config.xml 通过properties标签加载mysql.properties文件

    <properties resource="mysql.properties"></properties>
    
  • 在datasource配置中直接通过key进行引用

    <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
        <property name="driver" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </dataSource>
    
typeAliases 用于配置实体类的别名
<typeAliases>
    <typeAlias type="com.qfedu.pojo.Book" alias="Book"/>
</typeAliases>
plugins 用于配置MyBatis插件:分页插件
<!--用于配置MyBatis插件:分页插件-->
<plugins>
    <plugin interceptor=""></plugin>
</plugins>
environments 用于配置数据源
<!--在environments标签中可以通过environment配置多个数据源,default属性指定生效的数据库源-->
<environments default="mysql">
    <environment id="mysql">
        <!--指定mybatis的事务管理方式  JDBC   MANAGED
                JDBC   表示基于会话的事务管理  ==>  SqlSession
                MANAGED  表示MyBatis依靠容器完成事务管理
            -->
        <transactionManager type="JDBC"></transactionManager>
        <!--dataSource指定数据源,type用于指定DataSourceFactory,可以配置第三方连接池-->
        <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
            <property name="driver" value="${jdbc.driver}"/>
            <property name="url" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
</environments>
mappers 用于加载映射文件
<mappers>
    <mapper resource="mappers/BookMapper.xml"/>
</mappers>
8.2 MyBatis映射文件

映射文件,就是对DAO接口中数据库操作方法的实现

mapper根标签的namespace属性
  • namespace属性用于指定一个DAO接口的全限定名,用于声明当前mapper文件是对哪个接口的实现
catch标签 用于进行缓存配置
insert 标签

用于声明对添加操作的实现

delete标签

用于声明对删除操作的实现

update标签

用于声明对修改操作的实现

select标签

用于声明对查询操作的实现

sql 标签

用于定义sql片段

  • 定义sql片段

    <sql id="selectFields">
       book_id as bookId,book_name as bookName,book_author as bookAuthor,book_price as bookPrice
    </sql>
    
  • 引用sql片段

    <select id="getBook" resultType="Book">
        select <include refid="selectFields"/> from books where book_id=#{bookId}
    </select>
    
8.3 添加操作配置
8.3.1 DAO方法传递多个参数
  • 解决方案一:

    public int insertBook2(String bookName,String bookAuthor,double bookPrice);
    
    <insert id="insertBook2">
        insert into books(book_name,book_author,book_price)
        values(#{arg0},#{arg1},#{arg2})
    </insert>
    
  • 解决方案二:

    public int insertBook2(@Param("name")String bookName,
                           @Param("author")String bookAuthor,
                           @Param("price")double bookPrice);
    
    <insert id="insertBook2">
        insert into books(book_name,book_author,book_price)
        values(#{name},#{author},#{price})
    </insert>
    
8.3.2 主键回填

当执行添加操作时,如果主键是自动生成的,而我们完成添加操作之后想获得主键,可以通过主键回填实现

  • 解决方案一:
    <insert id="insertBook" useGeneratedKeys="true" keyProperty="bookId">
        insert into books(book_name,book_author,book_price)
        values(#{bookName},#{bookAuthor},#{bookPrice})
    </insert>
    
  • 解决方案二:
    <insert id="insertBook" >
      <selectKey keyProperty="bookId">
          select uuid()
      </selectKey>
      insert into books(book_name,book_author,book_price)
      values(#{bookName},#{bookAuthor},#{bookPrice})
    </insert>
    
8.4 查询操作配置
8.4.1 指定查询操作返回类型
  • 如果查询操作返回的是一条记录,则通过resultType执行封装结果的实体类即可(别名)

    <select id="getBook" resultType="Book">
        select <include refid="selectFields"/> from books where book_id=#{bookId}
    </select>
    
  • 如果查询操作返回的是多条记录,

    • 通过resultSets指定封装数据的集合类型(java.util.List) 此步骤可以省略
    • 需要通过resultType指定一条记录封装的实体对象类型
    <select id="listBooks" resultSets="java.util.List" resultType="Book">
        select <include refid="selectFields"/> from books
    </select>
    
8.4.2 ORM映射

ORM映射 , 从数据表中查询的结果需要封装到实体类对象,我们需要指定一条记录中的字段值和实体类对象的属性的对应关系

  • 第一种情况:如果实体类属性名数据表字段名 一一对应,则无需指定映射关系,MyBatis会自定将数据表字段的值封装到实体对象对应的属性中

  • 第二种情况:实体类属性名 与 数据表字段名不一致,则需指定映射关系:

    • 方案1:通过查询语句给字段设置别名,让别名与实体对象属性名一致即可

      <select id="getBook" resultType="Book">
          select book_id as bookId,book_name as bookName,book_author as bookAuthor,book_price as bookPrice from books where book_id=#{bookId}
      </select>
      
    • 方案2:通过结果集映射指定映射关系

      <resultMap id="bookMap" type="Book">
          <id column="book_id" property="bookId"/>
          <result column="book_name" property="bookName"/>
          <result column="book_author" property="bookAuthor"/>
          <result column="book_price" property="bookPrice"/>
      </resultMap>
      
      <!--    public Book getBook(int bookId);-->
      <select id="getBook"  resultMap="bookMap">
          select book_id,book_name,book_author,book_price from books where book_id=#{bookId}
      </select>
      
      <!--    public List<Book> listBooks();-->
      <select id="listBooks" resultMap="bookMap">
          select book_id,book_name,book_author,book_price from books
      </select>
      
8.5 MyBatis日志配置

日志,程序运行过程的记录

  • 添加日志框架依赖——log4j

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    
  • 在resources目录中创建log4j.properties文件

    # Global logging configuration
    # DEBUG  \  INFO  \ WARM \  ERROR 
    log4j.rootLogger=DEBUG, stdout
    # MyBatis logging configuration...
    log4j.logger.org.mybatis.example.BlogMapper=TRACE
    # Console output...
    log4j.appender.stdout=org.apache.log4j.ConsoleAppender
    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
    log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %n%m
    
    级别描述
    ALL LEVEL打开所有日志记录开关;是最低等级的,用于打开所有日志记录。
    DEBUG输出调试信息;指出细粒度信息事件对调试应用程序是非常有帮助的。
    INFO输出提示信息;消息在粗粒度级别上突出强调应用程序的运行过程。
    WARN输出警告信息;表明会出现潜在错误的情形。
    ERROR输出错误信息;指出虽然发生错误事件,但仍然不影响系统的继续运行。
    FATAL输出致命错误;指出每个严重的错误事件将会导致应用程序的退出。
    OFF LEVEL关闭所有日志记录开关;是最高等级的,用于关闭所有日志记录。

九、关联映射

因为实体与实体之间存在关系 --> 数据表与数据表之间会存在关联关系

9.1 实体与实体的关系

一对一 (用户信息,用户详情)

一对多 (班级 , 学生)

多对一 (学生,班级)

多对多 (学生,课程)

9.2 一对一

用户信息 — 用户详情

在这里插入图片描述

  • 建库建表

    -- 用户信息表
    create table users(
      user_id int primary key auto_increment,
    	user_name varchar(20) not null unique,
    	user_pwd varchar(16) not null
    );
    
    -- 用户详情表
    create table details(
      detail_id int primary key auto_increment,
    	user_realname varchar(20) not null,
    	user_gender char(2) not null,
    	user_id int not null unique,
    	constraint FK_USER foreign key(user_id) REFERENCES users(user_id)
    );
    
  • 创建实体类

    @Data
    public class User {
    
        private int userId;
        private String userName;
        private String userPwd;
        //一个用户信息包含一个详情信息
        private Detail detail;
    
    }
    
    @Data
    public class Detail {
    
        private int detailId;
        private String userRealname;
        private String userGender;
    	private int userId;
    }
    
  • 创建DAO接口

    public interface UserDAO {
    
        public int insertUser(User user);
        public User getUser(int userId);
    
    }
    
    public interface DetailDAO {
    
        public int insertDetail(Detail detail);
    
    }
    
添加操作—事务管理
  • 创建Mapper映射

    <!--UserMapper-->
    <insert id="insertUser" useGeneratedKeys="true" keyProperty="userId">
        insert into users(user_name,user_pwd) values(#{userName},#{userPwd});
    </insert>
    
    <!--DetailMapper-->
    <insert id="insertDetail" useGeneratedKeys="true" keyProperty="detailId">
        insert into details(user_realname,user_gender,user_id)
        values(#{userRealname},#{userGender},#{userId});
    </insert>
    
  • 测试添加操作

    @Test
    public void insertUser() {
        Detail detail = new Detail(0, "王三胖", "真的不详", 0);
        User user = new User(0,"hehehe","123456",detail);
    
        try{
            UserDAO userDAO = MyBatisUtil.getMapper(UserDAO.class);
            int i = userDAO.insertUser(user);
            System.out.println(user.getUserId());
    
            detail.setUserId(user.getUserId());
            DetailDAO detailDAO = MyBatisUtil.getMapper(DetailDAO.class);
            int j = detailDAO.insertDetail(detail);
    
            MyBatisUtil.commit();
            System.out.println(i+"---"+j);
        }catch (Exception e){
            MyBatisUtil.rollback();
        }
    
    }
    
查询操作—联合查询
  • 连接查询

    <resultMap id="userMap" type="User">
        <id column="user_id" property="userId"/>
        <result column="user_name" property="userName"/>
        <result column="user_pwd" property="userPwd"/>
        <result column="detail_id" property="detail.detailId"/>
        <result column="user_realname" property="detail.userRealname"/>
        <result column="user_gender" property="detail.userGender"/>
        <result column="user_id" property="detail.userId"/>
    </resultMap>
    
    <!-- public User getUser(int userId);-->
    <select id="getUser" resultMap="userMap">
        select u.*,d.detail_id,d.user_realname,d.user_gender
        from users u INNER JOIN details d on u.user_id=d.user_id
        where u.user_id=#{userId};
    </select>
    
    <resultMap id="userMap2" type="User">
        <id column="user_id" property="userId"/>
        <result column="user_name" property="userName"/>
        <result column="user_pwd" property="userPwd"/>
        <association property="detail" javaType="Detail">
            <result column="detail_id" property="detailId"/>
            <result column="user_realname" property="userRealname"/>
            <result column="user_gender" property="userGender"/>
            <result column="user_id" property="userId"/>
        </association>
    </resultMap>
    
    <!-- public User getUser(int userId);-->
    <select id="getUser" resultMap="userMap2">
        select u.*,d.detail_id,d.user_realname,d.user_gender
        from users u INNER JOIN details d on u.user_id=d.user_id
        where u.user_id=#{userId};
    </select>
    
  • 嵌套查询

    • DetailMapper
    <resultMap id="detailMap" type="Detail">
        <id column="detail_id" property="detailId"/>
        <result column="user_realname" property="userRealname"/>
        <result column="user_gender" property="userGender"/>
        <result column="user_id" property="userId"/>
    </resultMap>
    
    <!--    public Detail getDetailByUserId(int userId);-->
    <select id="getDetailByUserId" resultMap="detailMap">
        select * from details where user_id=#{userId}
    </select>
    
    • UserMapper
    <resultMap id="userMap3" type="User">
        <id column="user_id" property="userId"/>
        <result column="user_name" property="userName"/>
        <result column="user_pwd" property="userPwd"/>
        <association property="detail" column="user_id" 
                     select="com.qfedu.dao.DetailDAO.getDetailByUserId"/>
    </resultMap>
    
    <!-- public User getUser(int userId);-->
    <select id="getUser" resultMap="userMap3">
        select * from users where user_id=#{userId};
    </select>
    
9.3 一对多、多对一

班级 — 学生 : 在多的一端添加外键与一的一端主键进行关联

在这里插入图片描述

9.3.1 建表
create table classes(
    cid int primary key auto_increment,
    cname varchar(30) not null unique,
    cdesc varchar(100)
);

create table students(
    sid char(5) primary key,
    sname varchar(20) not null,
    sage int not null,
    cid int not null,
    constraint FK_CLASSES foreign key(cid) references classes(cid)
);
9.3.2 创建实体类

从一的一端体现关系(一对多):

  • 班级(一):

    public class Clazz{
        private int classId;
        private String className;
        private String classDesc;
        private List<Student> stus;
    }
    
  • 学生(多):

    public class Student{
        private String stuId;
        private String stuName;
        private int stuAge;
    }
    

从多的一端体现关系(多对一):

  • 班级(一):

    public class Clazz{
        private int classId;
        private String className;
        private String classDesc;
    }
    
  • 学生(多):

    public class Student{
        private String stuId;
        private String stuName;
        private int stuAge;
        private Clazz clazz;
    }
    
9.3.3 添加操作
    @Test
    public void insertClass() {
        List<Student> stus = new ArrayList<Student>();
        stus.add(new Student("10001","张三",20,0));
        stus.add(new Student("10002","李四",19,0));
        stus.add(new Student("10003","二狗",18,0));
        Clazz cla = new Clazz(0,"Java2001","777",stus);

        try {
            ClazzDAO clazzDAO = MyBatisUtil.getMapper(ClazzDAO.class);
            StudentDAO studentDAO = MyBatisUtil.getMapper(StudentDAO.class);

            int i = clazzDAO.insertClass(cla);
            for (Student s : cla.getStus()) {
                s.setCid(cla.getClassId());
                studentDAO.insertStudent(s);
            }

            MyBatisUtil.commit();
        }catch (Exception e){
            MyBatisUtil.rollback();
        }
    }
9.3.4 查询操作

一对多查询 查询班级同时级联查询到所有的学生

  • 连接查询

    public interface ClazzDAO {
    
        public Clazz getClazz(int cid);
    }
    
    <resultMap id="classMap" type="Clazz">
        <id column="cid" property="classId"/>
        <result column="cname" property="className"/>
        <result column="cdesc" property="classDesc"/>
        <collection property="stus" ofType="Student">
            <result column="sid" property="stuId"/>
            <result column="sname" property="stuName"/>
            <result column="sage" property="stuAge"/>
            <result column="cid" property="cid"/>
        </collection>
    </resultMap>
    
    <!--    public Clazz getClazz(int cid);-->
    <select id="getClazz" resultMap="classMap">
        select c.*, s.sid, s.sname, s.sage
        from classes c INNER JOIN students s on c.cid = s.cid
        where c.cid = #{cid}
    </select>
    
  • 嵌套查询

    <resultMap id="studentMap" type="Student">
        <id column="sid" property="stuId"/>
        <result column="sname" property="stuName"/>
        <result column="sage" property="stuAge"/>
        <result column="cid" property="cid"/>
    </resultMap>
    
    <!-- public List<Student> listStudentsByCid(int cid);-->
    <select id="listStudentsByCid" resultMap="studentMap">
        select * from students where cid=#{cid}
    </select>
    
    <resultMap id="classMap" type="Clazz">
        <id column="cid" property="classId"/>
        <result column="cname" property="className"/>
        <result column="cdesc" property="classDesc"/>
        <collection property="stus" column="cid" select="com.qfedu.dao.StudentDAO.listStudentsByCid"/>
    </resultMap>
    
    <!--    public Clazz getClazz(int cid);-->
    <select id="getClazz" resultMap="classMap">
        select * from classes where cid=#{cid}
    </select>
    

多对一查询 查询学生的时候级联查询此学生对应的班级

  • 连接查询

    <resultMap id="studentMap" type="Student">
        <id column="sid" property="stuId"/>
        <result column="sname" property="stuName"/>
        <result column="sage" property="stuAge"/>
        <association property="clazz" javaType="Clazz">
            <result column="cid" property="classId"/>
            <result column="cname" property="className"/>
            <result column="cdesc" property="classDesc"/>
        </association>
    </resultMap>
    <!--  public Student getStudent(String sid);-->
    <select id="getStudent" resultMap="studentMap">
        select s.*,c.cname,c.cdesc from students s inner join classes c
        on s.cid = c.cid
        where sid=#{sid}
    </select>
    
  • 嵌套查询(Java)

    <resultMap id="classMap" type="Clazz">
        <id column="cid" property="classId"/>
        <result column="cname" property="className"/>
        <result column="cdesc" property="classDesc"/>
    </resultMap>
    
    <!--    public Clazz getClassByCid(int cid);-->
    <select id="getClassByCid" resultMap="classMap">
        select * from classes where cid=#{cid}
    </select>
    
    <resultMap id="studentMap" type="Student">
        <id column="sid" property="stuId"/>
        <result column="sname" property="stuName"/>
        <result column="sage" property="stuAge"/>
        <association property="clazz" column="cid" select="com.qfedu.dao.ClazzDAO.getClassByCid"/>
    </resultMap>
    <!--  public Student getStudent(String sid);-->
    <select id="getStudent" resultMap="studentMap">
        select * from students
        where sid=#{sid}
    </select>
    
9.4 多对多

学生 — 课程 : 建立第三张表(关系表)

在这里插入图片描述

9.4.1 建表
create table students(
    sid char(5) primary key,
    sname varchar(20) not null   
);

create table courses(
   course_id int primary key auto_increment,
	 course_name varchar(100) not null
);

create table sc(
  sid char(5),
	cid int,
	constraint FK_STUDENTS foreign key(sid) references students(sid),
	constraint FK_COURSES foreign key(cid) references courses(course_id)
)
9.4.2 实体类
  1. 关系表仅仅维护 学生 和 课程 的 多对多关系,此时关系表就没有对应的实体类

在这里插入图片描述

  1. 关系表不仅维护 学生 和 课程 的 多对多关系,还提供了其他数据的存储 ==> 使用成绩表维护学生和课程的 多对多关系;在这种情况下,关系表需要对应实体类

在这里插入图片描述

十、动态SQL

根据条件动态完成SQL的拼接

10.1 sql片段
<sql id="fieldNames">
    id,nick,gender,imgurl,age,height, city,mdesc
</sql>

<select id="searchMembers" resultType="Member">
    select <include refid="fieldNames"/> from members
</select>
10.2 if
<select id="searchMembers" resultType="Member">
    select <include refid="fieldNames"/> from members where 1=1
    <if test="gender != null">
        and gender=#{gender}
    </if>
    <if test="city != null">
        and city=#{city}
    </if>
</select>
10.3 where
 <select id="searchMembers" resultType="Member">
     select <include refid="fieldNames"/> from members
     <where>
         <if test="gender != null">
             and gender=#{gender}
         </if>
         <if test="minAge != null">
             and age &gt;= #{minAge}
         </if>
         <if test="maxAge != null">
             and age &lt;= #{maxAge}
         </if>
         <if test="city != null">
             and city=#{city}
         </if>
     </where>
</select>
10.4 trim
 <select id="searchMembers" resultType="Member">
     select <include refid="fieldNames"/> from members    
	<trim prefix="where" prefixOverrides="AND|OR">
        <if test="gender != null">
            and gender=#{gender}
        </if>
        <if test="minAge != null">
            and age &gt;= #{minAge}
        </if>
        <if test="maxAge != null">
            and age &lt;= #{maxAge}
        </if>
        <if test="city != null">
            and city=#{city}
        </if>
    </trim>
</select>
10.5 foreach
<select id="">
    select * from members where id in
    <foreach collection="list" item="id" open="(" separator="," close=")">
        #{id}
    </foreach>
</select>

十一、缓存

缓存,就是内存中的一块存储空间,作用是将频繁操作的数据进行缓存,便于提升查询速度

在这里插入图片描述

11.1 一级缓存

一级缓存也称之为SqlSession级缓存,同一个SqlSession进行多次查询相同数据,会将数据保存在一级缓存中

在这里插入图片描述

11.2 二级缓存

二级缓存,也称为SqlSessionFactory缓存,需要通过配置开启;开启以后当前SqlSessionFactory创建的SqlSession可以共享这个二级缓存

  • 在mybatis-config.xml配置开启二级缓存

    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>
    
  • 在需要缓存的Mapper文件中配置缓存

    <cache/>
    
  • 存储在二级缓存的对象需要实现序列化接口

    public class Member implements Serializable {
       //...
    }
    

十二、整合druid连接池

MyBatis也提供了对第三方连接池的整合

  • 添加druid依赖

    <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.6</version>
    </dependency>
    
  • 创建配置类

    public class DruidDataSourceFactory extends PooledDataSourceFactory {
        public DruidDataSourceFactory() {
            this.dataSource = new DruidDataSource();
        }
    }
    
  • 在mybatis-config.xml进行配置(dataSource中使用的是DruidDataSource,属性名要使用DruidDataSource的属性名)

    <environment id="mysql">
        <transactionManager type="JDBC"></transactionManager>
        <dataSource type="com.qfedu.utils.DruidDataSourceFactory">
            <!--dataSource ==>  DruidDataSource -->
            <property name="driverClass" value="${jdbc.driver}"/>
            <property name="jdbcUrl" value="${jdbc.url}"/>
            <property name="username" value="${jdbc.username}"/>
            <property name="password" value="${jdbc.password}"/>
        </dataSource>
    </environment>
    

十三、分页插件

PageHelper是一款适用于MyBatis的分页插件

13.1 添加插件依赖
<!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper -->
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>5.1.10</version>
</dependency>
13.2 配置分页拦截器
<plugins>
    <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
</plugins>

十四、MyBatis的注解使用

1. 建表

2.创建实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Book {

    private int bookId;
    private String bookName;
    private String bookAuthor;
    private double bookPrice;

}
3.创建DAO接口
public interface BookDAO {
    
    public int insertBook(Book book);
    public int deleteBook(int bookId);
    public int updateBook(Book book);
    public Book getBook(int bookId);
    
}
4.在DAO方法上添加注解
public interface BookDAO {

    @Insert("insert into books(book_name,book_author,book_price) values(#{bookName},#{bookAuthor},#{bookPrice})")
    public int insertBook(Book book);

    @Delete("delete from books where book_id=#{bookId}")
    public int deleteBook(int bookId);

    //@Update("sql")
    // public int updateBook(Book book);

    @Select("select book_id as bookId,book_name as bookName,book_author as bookAuthor," +
            "book_price as bookPrice from books where book_id=#{bookId}")
    public Book getBook(int bookId);

}
5.将DAO接口配置到mybatis-config.xml
<mappers>
    <mapper class="com.qfedu.dao.BookDAO"/>
</mappers>

十五、延迟加载

延迟加载 —— 如果开启了延迟加载,在嵌套关联查询中,默认先执行最上层的查询不执行关联查询,当我们需要使用关联数据时,才发送查询请求执行查询。

如何启用延迟加载:

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

在这里插入图片描述

十六、$和#

${} 和 #{} 都可以用来获取DAO方法传递的参数

${} 表示将获取的参数拼接到SQL语句,可能导致SQL注入

#{}表示SQL采用预编译,然后在进行参数的赋值,可以避免SQL的注入问题

2020.07.27 练习任务

1. 使用MyBatis完成单表的CRUD
  • 添加操作(主键回填)
  • 根据主键删除
  • 根据主键修改其他字段
  • 根据主键查询一条记录
  • 查询所有记录
  • 分页
    • 统计总记录数
    • 分页查询
2. 一对一关联练习
  • 完成课堂案例(自己列举一个一对一案例,然后完成)

2020年7月28日 练习任务

1. 一对多和多对多关联练习
  • 课堂案例
2. 动态sql案例
  • 珍爱网会员搜索
  • 使用Druid连接池
  • 使用PageHelper插件分页

blic Book getBook(int bookId);

}


#### 4.在DAO方法上添加注解

```java
public interface BookDAO {

    @Insert("insert into books(book_name,book_author,book_price) values(#{bookName},#{bookAuthor},#{bookPrice})")
    public int insertBook(Book book);

    @Delete("delete from books where book_id=#{bookId}")
    public int deleteBook(int bookId);

    //@Update("sql")
    // public int updateBook(Book book);

    @Select("select book_id as bookId,book_name as bookName,book_author as bookAuthor," +
            "book_price as bookPrice from books where book_id=#{bookId}")
    public Book getBook(int bookId);

}
5.将DAO接口配置到mybatis-config.xml
<mappers>
    <mapper class="com.qfedu.dao.BookDAO"/>
</mappers>

十五、延迟加载

延迟加载 —— 如果开启了延迟加载,在嵌套关联查询中,默认先执行最上层的查询不执行关联查询,当我们需要使用关联数据时,才发送查询请求执行查询。

如何启用延迟加载:

<settings>
    <setting name="lazyLoadingEnabled" value="true"/>
</settings>

[外链图片转存中…(img-mcSe57CX-1596019169831)]

十六、$和#

${} 和 #{} 都可以用来获取DAO方法传递的参数

${} 表示将获取的参数拼接到SQL语句,可能导致SQL注入

#{}表示SQL采用预编译,然后在进行参数的赋值,可以避免SQL的注入问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值