image.png

Author:Aaron

Version:9.0.2

一、引言


1.1 什么是框架?

软件的半成品,解决了软件开发过程当中的普适性问题,从而简化了开发步骤,提供了开发的效率。

1.2 什么是ORM框架?

  • ORM(Object Relational Mapping)对象关系映射,将程序中的一个对象与表中的一行数据一一对应。
  • ORM框架提供了持久化类与表的映射关系,在运行时参照映射文件的信息,把对象持久化到数据库中`。

1.3 使用JDBC完成ORM操作的缺点?

  • 存在大量的冗余代码。
  • 手工创建 Connection、Statement 等。
  • 手工将结果集封装成实体对象。
  • 查询效率低,没有对数据访问进行过优化(Not Cache)。

二、MyBatis框架


2.1 概念

  • MyBatis本是Apache软件基金会的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了Google Code,并且改名为MyBatis 。2013年11月迁移到Github。
  • MyBatis是一个优秀的基于Java的持久层框架,支持自定义SQL,存储过程和高级映射。
  • MyBatis对原有JDBC操作进行了封装,几乎消除了所有JDBC代码,使开发者只需关注 SQL 本身。
  • MyBatis可以使用简单的XML或Annotation来配置执行SQL,并自动完成ORM操作,将执行结果返回。

2.2 访问与下载

官方网站:http://www.mybatis.org/mybatis-3/

下载地址:https://github.com/mybatis/mybatis-3/releases/tag/mybatis-3.5.1

三、构建Maven项目


3.1 新建项目

使用IDEA打开已创建的文件夹目录
image.png

3.2 选择Maven目录

选择Maven项目
image.png

3.3 GAV坐标

GAV坐标
image.png

四、MyBatis环境搭建【重点


4.1 pom.xml中引入MyBatis核心依赖

在pom.xml中引入相关依赖

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0"
  3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  4. xsi:schemaLocation=
  5. "http://maven.apache.org/POM/4.0.0
  6. http://maven.apache.org/xsd/maven-4.0.0.xsd">
  7. <modelVersion>4.0.0</modelVersion>
  8. <!--项目配置-->
  9. <groupId>com.qf</groupId>
  10. <artifactId>hello-mybatis</artifactId>
  11. <version>1.0-SNAPSHOT</version>
  12. <!--依赖-->
  13. <dependencies>
  14. <!--MyBatis核心依赖-->
  15. <dependency>
  16. <groupId>org.mybatis</groupId>
  17. <artifactId>mybatis</artifactId>
  18. <version>3.4.6</version>
  19. </dependency>
  20. <!--MySql驱动依赖-->
  21. <dependency>
  22. <groupId>mysql</groupId>
  23. <artifactId>mysql-connector-java</artifactId>
  24. <version>5.1.47</version>
  25. </dependency>
  26. </dependencies>
  27. </project>

4.2 创建MyBatis配置文件

创建并配置mybatis-config.xml

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <!--MyBatis配置-->
  5. <configuration>
  6. <!--JDBC环境配置、选中默认环境-->
  7. <environments default="MySqlDB">
  8. <!--MySql数据库环境配置-->
  9. <environment id="MySqlDB">
  10. <!--事务管理-->
  11. <transactionManager type="JDBC"/>
  12. <!--连接池-->
  13. <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
  14. <property name="driver" value="com.mysql.jdbc.Driver"/>
  15. <!-- &转义&amp; -->
  16. <property name="url" value="jdbc:mysql://localhost:3306/x?useUnicode=true&amp;characterEncoding=utf-8"/>
  17. <property name="username" value="xxx"/>
  18. <property name="password" value="xxx"/>
  19. </dataSource>
  20. </environment>
  21. </environments>
  22. <!--Mapper注册-->
  23. <mappers>
  24. <!--注册Mapper文件的所在位置-->
  25. <mapper resource="xxxMapper.xml"/>
  26. </mappers>
  27. </configuration>
  • 注意:mapper.xml默认建议存放在resources中,路径不能以/开头

五、MyBatis开发步骤【重点


5.1 建表

  1. create table t_users(
  2. id int primary key auto_increment,
  3. name varchar(50),
  4. password varchar(50),
  5. sex varchar(1),
  6. birthday datetime,
  7. registTime datetime
  8. )default charset = utf8;

5.2 定义实体类

定义所需CURD操作的实体类

  1. package com.qf.mybatis.part1.basic;
  2. public class User {
  3. private Integer id;
  4. private String name;
  5. private String password;
  6. private String sex;
  7. private Date birthday;
  8. private Date registTime;
  9. //无参构造(必备构造二选一)
  10. public User() {}
  11. //全参构造(必备构造二选一)
  12. public User(Integer id, String name, String password, String sex, Date birthday, Date registTime) {
  13. this.id = id;
  14. this.name = name;
  15. this.password = password;
  16. this.sex = sex;
  17. this.birthday = birthday;
  18. this.registTime = registTime;
  19. }
  20. //Getters And Setters
  21. }

5.3 定义DAO接口

根据所需DAO定义接口、以及方法

  1. package com.qf.mybatis.part1.basic;
  2. public interface UserDao {
  3. public User selectUserById(Integer id);
  4. }

5.4 编写Mapper.xml

在resources目录中创建Mapper.xml文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
  4. <!--namespace = 所需实现的接口全限定名-->
  5. <mapper namespace="com.qf.mybatis.part1.basic.UserDao">
  6. <!--id = 所需重写的接口抽象方法,resultType = 查询后所需返回的对象类型-->
  7. <select id="selectUserById" resultType="com.qf.mybatis.part1.basic.User">
  8. <!--#{arg0} = 方法的第一个形参-->
  9. SELECT * FROM t_users WHERE id = #{arg0}
  10. </select>
  11. </mapper>

5.5 注册Mapper

将Mapper.xml注册到mybatis-config.xml中

  1. <!--Mapper文件注册位置-->
  2. <mappers>
  3. <!--注册Mapper文件-->
  4. <mapper resource="UserDaoMapper.xml"/>
  5. </mappers>

5.6 测试一

MyBatis的API操作方式

  1. package com.qf.mybatis.part1.basic;
  2. import org.apache.ibatis.io.Resources;
  3. import org.apache.ibatis.session.SqlSession;
  4. import org.apache.ibatis.session.SqlSessionFactory;
  5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  6. import org.junit.Test;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. public class HelloMyBatis {
  10. @Test
  11. public void test1() throws IOException {
  12. //1.获得读取MyBatis配置文件的流对象
  13. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
  14. //2.构建SqlSession连接对象的工厂
  15. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
  16. //3.通过工厂获得连接对象
  17. SqlSession sqlSession = factory.openSession();
  18. //4.通过连接对象获得接口实现类对象
  19. UserDao userDao = sqlSession.getMapper(UserDao.class);
  20. //5.调用接口中的方法
  21. System.out.println(userDao.selectUserById(1));
  22. }
  23. }

5.7 测试二【了解】

iBatis传统操作方式

  1. package com.qf.mybatis.part1.basic;
  2. import org.apache.ibatis.io.Resources;
  3. import org.apache.ibatis.session.SqlSession;
  4. import org.apache.ibatis.session.SqlSessionFactory;
  5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  6. import org.junit.Test;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. public class HelloMyBatis {
  10. @Test
  11. public void test2() throws IOException {
  12. //1.获得读取MyBatis配置文件的流对象
  13. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
  14. //2.构建SqlSession连接对象的工厂
  15. SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(is);
  16. //3.通过工厂获得连接对象
  17. SqlSession sqlSession = factory.openSession();
  18. //4.通过连接对象直接调用接口中的方法
  19. Object o = sqlSession.selectOne("com.qf.mybatis.part1.basic.UserDao.selectUserById", 1);
  20. System.out.println(o);
  21. }
  22. }

六、细节补充


6.1 解决mapper.xml存放在resources以外路径中的读取问题(了解)

在pom.xml文件最后追加< build >标签,以便可以将xml文件复制到classes中,并在程序运行时正确读取。

  1. <build>
  2. <resources>
  3. <resource>
  4. <directory>src/main/java</directory>
  5. <includes>
  6. <include>*.xml</include><!-- 默认(新添加自定义则失效) -->
  7. <include>**/*.xml</include><!-- 新添加 */代表1级目录 **/代表多级目录 -->
  8. </includes>
  9. <filtering>true</filtering>
  10. </resource>
  11. </resources>
  12. </build>

6.2 properties配置文件

对于mybatis-config.xml的核心配置中,如果存在需要频繁改动的数据内容,可以提取到properties中。

  1. #jdbc.properties
  2. jdbc.driver=com.mysql.jdbc.Driver
  3. jdbc.url=jdbc:mysql://localhost:3306/example?useUnicode=true&characterEncpding=utf8
  4. jdbc.username=root
  5. jdbc.password=123456

修改mybatis-config.xml。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <configuration>
  5. <!--添加properties配置文件路径(外部配置、动态替换)-->
  6. <properties resource="jdbc.properties" />
  7. <environments default="MySqlDB">
  8. <environment id="MySqlDB">
  9. <transactionManager type="JDBC"/>
  10. <dataSource type="POOLED">
  11. <!--使用$ + 占位符-->
  12. <property name="driver" value="${driver}"/>
  13. <property name="url" value="${url}"/>
  14. <property name="username" value="${username}"/>
  15. <property name="password" value="${password}"/>
  16. </dataSource>
  17. </environment>
  18. </environments>
  19. <mappers>
  20. <mapper resource="UserDaoMapper.xml" />
  21. </mappers>
  22. </configuration>

6.3 类型别名

为实体类定义别名,提高书写效率。

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
  3. "http://mybatis.org/dtd/mybatis-3-config.dtd">
  4. <configuration>
  5. <properties ... />
  6. <!--定义别名二选一-->
  7. <typeAliases>
  8. <!--定义类的别名-->
  9. <typeAlias type="com.qf.mybatis.part1.basic.User" alias="user" />
  10. <!--自动扫描包,将原类名作为别名-->
  11. <package name="com.qf.mybatis.part1.basic" />
  12. </typeAliases>
  13. ...
  14. </configuration>

6.4 创建log4j配置文件

pom.xml添加log4j依赖 log

  1. <!-- log4j日志依赖 https://mvnrepository.com/artifact/log4j/log4j -->
  2. <dependency>
  3. <groupId>log4j</groupId>
  4. <artifactId>log4j</artifactId>
  5. <version>1.2.17</version>
  6. </dependency>

创建并配置log4j.properties

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

七、MyBatis的CRUD操作【重点


7.1 查询

标签:< select id=”” resultType=”” >

7.1.1 序号参数绑定
  1. public interface UserDao {
  2. //使用原生参数绑定
  3. public User selectUserByIdAndPwd(Integer id , String pwd);
  4. }
  1. <select id="selectUserByIdAndPwd" resultType="user">
  2. SELECT * FROM t_users
  3. WHERE id = #{arg0} AND password = #{arg1} <!--arg0 arg1 arg2 ...-->
  4. </select>
  5. <select id="selectUserByIdAndPwd" resultType="user">
  6. SELECT * FROM t_users
  7. WHERE id = #{param1} AND password = #{param2} <!--param1 param2 param3 ...-->
  8. </select>

7.1.2 注解参数绑定【推荐】
  1. import org.apache.ibatis.annotations.Param; //引入注解
  2. public interface UserDao {
  3. //使用MyBatis提供的@Param进行参数绑定
  4. public User selectUserByIdAndPwd(@Param("id") Integer id , @Param("pwd") String pwd);
  5. }
  1. <select id="selectUserByIdAndPwd" resultType="user">
  2. SELECT * FROM t_users
  3. WHERE id = #{id} AND password = #{pwd} <!-- 使用注解值 @Param("pwd") -->
  4. </select>

7.1.3 Map参数绑定
  1. public interface UserDao {
  2. //添加Map进行参数绑定
  3. public User selectUserByIdAndPwd_map(Map values);
  4. }
  1. Map values = new HashMap(); //测试类创建Map
  2. values.put("myId",1); //自定义key,绑定参数
  3. values.put("myPwd","123456");
  4. User user = userDao.selectUserByIdAndPwd_map(values);
  1. <select id="selectUserByIdAndPwd_map" resultType="user">
  2. SELECT * FROM t_users
  3. WHERE id = #{myId} AND password = #{myPwd} <!-- 通过key获得value -->
  4. </select>

7.1.4 对象参数绑定
  1. public interface UserDao {
  2. //使用对象属性进行参数绑定
  3. public User selectUserByUserInfo(User user);
  4. }
  1. <select id="selectUserByUserInfo" resultType="user">
  2. SELECT * FROM t_users
  3. WHERE id = #{id} AND password = #{password} <!-- #{id}取User对象的id属性值、#{password}同理 -->
  4. </select>

7.1.5 模糊查询
  1. public interface UserDao {
  2. public List<User> selectUsersByKeyword(@Param("keyword") String keyword);
  3. }
  1. <mapper namespace="com.qf.mybatis.part1.different.UserDao">
  2. <select id="selectUsersByKeyword" resultType="user">
  3. SELECT * FROM t_users
  4. WHERE name LIKE concat('%',#{keyword},'%') <!-- 拼接'%' -->
  5. </select>
  6. </mapper>

7.2 删除

标签:< delete id=”” parameterType=”” >

  1. <delete id="deleteUser" parameterType="int">
  2. DELETE FROM t_users
  3. WHERE id = #{id} <!--只有一个参数时,#{任意书写}-->
  4. </delete>

7.3 修改

标签:< update id=”” parameterType=”” >

  1. <update id="updateUser" parameterType="user">
  2. UPDATE t_users SET name=#{name}, password=#{password}, sex=#{sex}, birthday=#{birthday}
  3. WHERE id = #{id} <!--方法参数为对象时,可直接使用#{属性名}进行获取-->
  4. </update>

7.4 添加

标签:< insert id=”” parameterType=”” >

  1. <!--手动主键-->
  2. <insert id="insertUser" parameterType="user">
  3. INSERT INTO t_users VALUES(#{id},#{name},#{password},#{sex},#{birthday},NULL);
  4. </insert>
  5. <!--自动主键-->
  6. <insert id="insertUser" parameterType="user">
  7. <!-- 自动增长主键,以下两种方案均可 -->
  8. INSERT INTO t_users VALUES(#{id},#{name},#{password},#{sex},#{birthday},NULL);
  9. INSERT INTO t_users VALUES(NULL,#{name},#{password},#{sex},#{birthday},NULL);
  10. </insert>

7.5 主键回填

标签:< selectKey id=”” parameterType=”” order=”AFTER|BEFORE”>

7.5.1 通过last_insert_id()查询主键
  1. create table t_product(
  2. id int primary key auto_increment,
  3. name varchar(50)
  4. )default charset = utf8;
  1. class Product{
  2. private Integer id;
  3. private String name;
  4. //set+get ...
  5. }
  1. <mapper namespace="com.qf.mybatis.part1.basic.ProductDao">
  2. <insert id="insertProduct" parameterType="product">
  3. <selectKey keyProperty="id" resultType="int" order="AFTER"> <!-- 插入之后 -->
  4. SELECT LAST_INSERT_ID() <!-- 适用于整数类型自增主键 -->
  5. </selectKey>
  6. INSERT INTO t_product(id,name) VALUES(#{id},#{name})
  7. </insert>
  8. </mapper>

7.5.2 通过uuid()查询主键
  1. create table t_order(
  2. id varchar(32) primary key, # 字符型主键
  3. name varchar(50)
  4. )default charset = utf8;
  1. class Order{
  2. private String id;
  3. private String name;
  4. //set+get ...
  5. }
  1. <mapper namespace="com.qf.mybatis.part1.basic.OrderDao">
  2. <insert id="insertOrder" parameterType="order">
  3. <selectKey keyProperty="id" resultType="String" order="BEFORE"><!-- 插入之前 -->
  4. SELECT REPLACE(UUID(),'-','') <!-- 适用于字符类型主键 -->
  5. </selectKey>
  6. INSERT INTO t_order(id,name) VALUES(#{id},#{name})
  7. </insert>
  8. </mapper>

八、MyBatis工具类【非重点


8.1 封装工具类

  • Resource:用于获得读取配置文件的IO对象,耗费资源,建议通过IO一次性读取所有所需要的数据。
  • SqlSessionFactory:SqlSession工厂类,内存占用多,耗费资源,建议每个应用只创建一个对象。
  • SqlSession:相当于Connection,可控制事务,应为线程私有,不被多线程共享。
  • 将获得连接、关闭连接、提交事务、回滚事务、获得接口实现类等方法进行封装。
  1. package com.qf.mybatis.part1.utils;
  2. import org.apache.ibatis.io.Resources;
  3. import org.apache.ibatis.session.SqlSession;
  4. import org.apache.ibatis.session.SqlSessionFactory;
  5. import org.apache.ibatis.session.SqlSessionFactoryBuilder;
  6. import java.io.InputStream;
  7. public class MyBatisUtils {
  8. //获得SqlSession工厂
  9. private static SqlSessionFactory factory;
  10. //创建ThreadLocal绑定当前线程中的SqlSession对象
  11. private static final ThreadLocal<SqlSession> tl = new ThreadLocal<SqlSession>();
  12. static {
  13. try {
  14. InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
  15. factory = new SqlSessionFactoryBuilder().build(is);
  16. } catch (Exception e) {
  17. e.printStackTrace();
  18. }
  19. }
  20. //获得连接(从tl中获得当前线程SqlSession)
  21. private static SqlSession openSession(){
  22. SqlSession session = tl.get();
  23. if(session == null){
  24. session = factory.openSession();
  25. tl.set(session);
  26. }
  27. return session;
  28. }
  29. //释放连接(释放当前线程中的SqlSession)
  30. private static void closeSession(){
  31. SqlSession session = tl.get();
  32. session.close();
  33. tl.remove();
  34. }
  35. //提交事务(提交当前线程中的SqlSession所管理的事务)
  36. public static void commit(){
  37. SqlSession session = openSession();
  38. session.commit();
  39. closeSession();
  40. }
  41. //回滚事务(回滚当前线程中的SqlSession所管理的事务)
  42. public static void rollback(){
  43. SqlSession session = openSession();
  44. session.rollback();
  45. closeSession();
  46. }
  47. //获得接口实现类对象
  48. public static <T extends Object> T getMapper(Class<T> clazz){
  49. SqlSession session = openSession();
  50. return session.getMapper(clazz);
  51. }
  52. }

8.2 测试工具类

调用MyBatisUtils中的封装方法。

  1. @Test
  2. public void testUtils() {
  3. try {
  4. UserDao userDao = MyBatisUtils.getMapper(UserDao.class);
  5. userDao.deleteUser(15);
  6. MyBatisUtils.commit();
  7. } catch (Exception e) {
  8. MyBatisUtils.rollback();
  9. e.printStackTrace();
  10. }
  11. }

九、ORM映射【重点


9.1 MyBatis自动(反射 get和set)ORM失效

MyBatis只能自动维护库表”列名“与”属性名“相同时的一一对应关系,二者不同时,无法自动ORM。

自动ORM失效
image.png

9.2 方案一:列的别名

在SQL中使用 as 为查询字段添加列别名,以匹配属性名。

  1. <mapper namespace="com.qf.mybatis.part2.orm.ManagerDao">
  2. <select id="selectManagerByIdAndPwd" resultType="com.qf.mybatis.part2.orm.Manager">
  3. SELECT mgr_id AS id , mgr_name AS username , mgr_pwd AS password
  4. FROM t_managers
  5. WHERE mgr_id = #{id} AND mgr_pwd = #{pwd}
  6. </select>
  7. </mapper>

9.3 方案二:结果映射(ResultMap - 查询结果的封装规则)

通过< resultMap id=”” type=”” >映射,匹配列名与属性名。

  1. <mapper namespace="com.qf.mybatis.part2.orm.ManagerDao">
  2. <!--定义resultMap标签-->
  3. <resultMap id="managerResultMap" type="com.qf.mybatis.part2.orm.Manager">
  4. <!--关联主键与列名-->
  5. <id property="id" column="mgr_id" />
  6. <!--关联属性与列名-->
  7. <result property="username" column="mgr_name" />
  8. <result property="password" column="mgr_pwd" />
  9. </resultMap>
  10. <!--使用resultMap作为ORM映射依据-->
  11. <select id="selectAllManagers" resultMap="managerResultMap">
  12. SELECT mgr_id , mgr_name , mgr_pwd
  13. FROM t_managers
  14. </select>
  15. </mapper>

十、MyBatis处理关联关系-多表连接【重点

10.0 连表查询三种方式

1、使用vo查询

编写vo对象

  1. package com.qf.entity.vo;
  2. import java.io.Serializable;
  3. public class UserVo implements Serializable {
  4. private Integer userId;
  5. private String userName;
  6. private String phone;
  7. private String pwd;
  8. private String account;
  9. private Integer authId;
  10. private String authName;
  11. private String url;
  12. public Integer getUserId() {
  13. return userId;
  14. }
  15. public void setUserId(Integer userId) {
  16. this.userId = userId;
  17. }
  18. public String getUserName() {
  19. return userName;
  20. }
  21. public void setUserName(String userName) {
  22. this.userName = userName;
  23. }
  24. public String getPhone() {
  25. return phone;
  26. }
  27. public void setPhone(String phone) {
  28. this.phone = phone;
  29. }
  30. public String getPwd() {
  31. return pwd;
  32. }
  33. public void setPwd(String pwd) {
  34. this.pwd = pwd;
  35. }
  36. public String getAccount() {
  37. return account;
  38. }
  39. public void setAccount(String account) {
  40. this.account = account;
  41. }
  42. public Integer getAuthId() {
  43. return authId;
  44. }
  45. public void setAuthId(Integer authId) {
  46. this.authId = authId;
  47. }
  48. public String getAuthName() {
  49. return authName;
  50. }
  51. public void setAuthName(String authName) {
  52. this.authName = authName;
  53. }
  54. public String getUrl() {
  55. return url;
  56. }
  57. public void setUrl(String url) {
  58. this.url = url;
  59. }
  60. @Override
  61. public String toString() {
  62. return "UserVo{" +
  63. "userId=" + userId +
  64. ", userName='" + userName + '\'' +
  65. ", phone='" + phone + '\'' +
  66. ", pwd='" + pwd + '\'' +
  67. ", account='" + account + '\'' +
  68. ", authId=" + authId +
  69. ", authName='" + authName + '\'' +
  70. ", url='" + url + '\'' +
  71. '}';
  72. }
  73. }

编写sql

  1. select u.*,a.`name` as authName,a.url as url
  2. from t_user u
  3. LEFT JOIN t_auth a on u.roleNum=a.id where u.id=#{id}

map映射

  1. <resultMap id="userAuth" type="com.qf.entity.vo.UserVo">
  2. <id property="userId" column="id" javaType="int"/>
  3. <result property="userName" column="name"/>
  4. <result property="phone" column="phone"/>
  5. <result property="pwd" column="pwd"/>
  6. <result property="account" column="accout"/>
  7. <result property="authId" column="roleNum"/>
  8. <result property="authName" column="authName"/>
  9. <result property="url" column="url"/>
  10. </resultMap>

dao层接口

  1. public List<UserVo> findByUserId(Integer id);

2、使用map集合查询

resultType=”map” 指定Map集合对象

  1. <select id="queryUserId" resultType="map">
  2. select u.*,a.`name` as authName,a.url as url
  3. from t_user u
  4. LEFT JOIN t_auth a on u.roleNum=a.id where u.id=#{id}
  5. </select>

dao接口

  1. public Map<String,Object> queryUserId(Integer id);

测试结果

  1. @Test
  2. public void queryUserId(){
  3. SqlSession sqlSession = MyBatiesUtil.getSqlSession();
  4. UserDao mapper = sqlSession.getMapper(UserDao.class);
  5. Map<String, Object> stringObjectMap = mapper.queryUserId(1);
  6. System.out.println(stringObjectMap);
  7. MyBatiesUtil.close(sqlSession);
  8. }

实体间的关系:关联关系(拥有 has、属于 belong)

  • OneToOne:一对一关系(Passenger—- Passport)
  • OneToMany:一对多关系(Employee —- Department)
  • ManyToMany:多对多关系(Student —- Subject)
Table建立外键关系
image.png
Entity添加关系属性
image.png
Mapper中将属性与列名对应
image.png

3、使用对象关系查询

10.1 OneToOne

SQL参考OneToOneExample.sql

  1. <mapper namespace="com.qf.mybatis.part2.one2one.PassengerDao">
  2. <!-- 结果映射(查询结果的封装规则) -->
  3. <resultMap id="passengerResultMap" type="com.qf.mybatis.part2.one2one.Passenger">
  4. <id property="id" column="id"/>
  5. <result property="name" column="name" />
  6. <result property="sex" column="sex" />
  7. <result property="birthday" column="birthday" />
  8. <!-- 关系表中数据的封装规则 --> <!-- 指定关系表的实体类型 -->
  9. <association property="passport" javaType="com.qf.mybatis.part2.one2one.Passport">
  10. <id property="id" column="passport_id" />
  11. <result property="nationality" column="nationality" />
  12. <result property="expire" column="expire" />
  13. <result property="passenger_id" column="passenger_id" />
  14. </association>
  15. </resultMap>
  16. <!-- 多表连接查询 --> <!-- 结果映射(查询结果的封装规则)-->
  17. <select id="selectPassengerById" resultMap="passengerResultMap">
  18. <!-- 别名(避免与p1.id冲突) -->
  19. SELECT p1.id , p1.name , p1.sex , p1.birthday , p2.id as passport_id , p2.nationality , p2.expire , p2.passenger_id
  20. FROM t_passengers p1 LEFT JOIN t_passports p2
  21. ON p1.id = p2.passenger_id
  22. WHERE p1.id = #{id}
  23. </select>
  24. </mapper>
  • 注意:指定“一方”关系时(对象),使用< association javaType=”” >

10.2 OneToMany

SQL参考OneToManyExample.sql

  1. <mapper namespace="com.qf.mybatis.part2.one2many.DepartmentDao">
  2. <!-- 封装规则 -->
  3. <resultMap id="departmentResultMap" type="com.qf.mybatis.part2.one2many.Department">
  4. <id property="id" column="id" />
  5. <result property="name" column="name" />
  6. <result property="location" column="location" />
  7. <!-- 关系表中数据的封装规则 --> <!-- 指定关系表的实体类型 -->
  8. <collection property="emps" ofType="com.qf.mybatis.part2.one2many.Employee">
  9. <id property="id" column="emp_id" />
  10. <result property="name" column="emp_name" />
  11. <result property="salary" column="salary" />
  12. <result property="dept_id" column="dept_id" />
  13. </collection>
  14. </resultMap>
  15. <!-- 多表连接查询 --> <!-- 封装规则 -->
  16. <select id="selectDepartmentById" resultMap="departmentResultMap" >
  17. <!-- 别名(避免与d.id、d.name冲突)-->
  18. SELECT d.id , d.name , d.location , e.id AS emp_id , e.name emp_name , e.salary , e.dept_id
  19. FROM t_departments d LEFT JOIN t_employees e
  20. ON d.id = e.dept_id
  21. WHERE d.id = #{id}
  22. </select>
  23. </mapper>
  • 注意:指定“多方”关系时(集合),使用< collection ofType=”” >

10.3 ManyToMany

SQL参考ManyToManyExample.sql

建立第三张关系表
image.png
  1. <mapper namespace="com.qf.mybatis.part2.many2many.StudentDao">
  2. <!-- 映射查询只封装两表中的信息,可忽略关系表内容 -->
  3. <resultMap id="allMap" type="com.qf.mybatis.part2.many2many.Student">
  4. <id property="id" column="id" />
  5. <result property="name" column="name" />
  6. <result property="sex" column="sex" />
  7. <collection property="subjects" ofType="com.qf.mybatis.part2.many2many.Subject">
  8. <id property="id" column="sid" />
  9. <result property="name" column="sname" />
  10. <result property="grade" column="grade" />
  11. </collection>
  12. </resultMap>
  13. <!-- 三表连接查询 -->
  14. <select id="selectAllStudents" resultMap="allMap">
  15. SELECT s1.* , ss.* , s2.id as sid , s2.name as sname , s2.grade
  16. FROM t_students s1 LEFT JOIN t_stu_sub ss
  17. ON s1.id = ss.student_id <!-- 通过t_stu_sub表建立二者之间的关系 -->
  18. LEFT JOIN t_subjects s2
  19. ON ss.subject_id = s2.id
  20. </select>
  21. </mapper>
  • 注意:指定“多方”关系时(集合),使用< collection ofType=”” >

10.4 关系总结

一方,添加集合;多方,添加对象。

双方均可建立关系属性,建立关系属性后,对应的Mapper文件中需使用< ResultMap >完成多表映射。

持有对象关系属性,使用< association property=”dept” javaType=”department” >

持有集合关系属性,使用< collection property=”emps” ofType=”employee” >

作业:用户表和角色表,编写一对一关系 、一对多、多对一、多对对 双向
一对一: user—》role 首先查询 根据用户查角色,反向-》角色查用户
一对多: 用户查角色;角色查询用户

多对多:双向

采用mybatis 查询递归 区域表

十一、动态SQL【重点


MyBatis的映射文件中支持在基础SQL上添加一些逻辑操作,并动态拼接成完整的SQL之后再执行,以达到SQL复用、简化编程的效果。

11.1 < sql >

  1. <mapper namespace="com.qf.mybatis.part2.dynamic.BookDao">
  2. <sql id="BOOKS_FIELD"> <!-- 定义SQL片段 -->
  3. SELECT id,name,author,publish,sort
  4. </sql>
  5. <select id="selectBookByCondition" resultType="com.qf.mybatis.part2.dynamic.Book">
  6. <include refid="BOOKS_FIELD" /> <!-- 通过ID引用SQL片段 -->
  7. FROM t_books
  8. </select>
  9. </mapper>

11.2 < if >

  1. <select id="selectBookByCondition" resultType="com.qf.mybatis.part2.dynamic.Book">
  2. <include refid="BOOKS_FIELD" /> <!-- 通过ID引用SQL片段 -->
  3. FROM t_books
  4. <if test="name!=null">
  5. name=#{name}
  6. </if>
  7. <if test="author!=null">
  8. and author=#{author}
  9. </if>
  10. </select>

11.3 < where >

  1. <select id="selectBookByCondition" resultType="com.qf.mybatis.part2.dynamic.Book">
  2. SELECT id , name , author , publish , sort
  3. FROM t_books
  4. <where>
  5. <if test="id != null"> <!-- WHERE,会自动忽略前后缀(如:and | or) -->
  6. id = #{id}
  7. </if>
  8. <if test="name != null">
  9. and name = #{name}
  10. </if>
  11. <if test="author != null">
  12. and author = #{author}
  13. </if>
  14. <if test="publish != null">
  15. and publish = #{publish}
  16. </if>
  17. <if test="sort != null">
  18. and sort = #{sort}
  19. </if>
  20. </where>
  21. </select>

11.4 < set >

  1. <update id="updateBookByCondition">
  2. UPDATE t_books
  3. <set>
  4. <if test="name != null"><!-- where子句中满足条件的if,会自动忽略后缀(如:,) -->
  5. name = #{name} ,
  6. </if>
  7. <if test="author != null">
  8. author = #{author} ,
  9. </if>
  10. <if test="publish != null">
  11. publish = #{publish} ,
  12. </if>
  13. <if test="sort != null">
  14. sort = #{sort} ,
  15. </if>
  16. </set>
  17. WHERE id = #{id}
  18. </update>

11.5 < trim >

< trim prefix=”” suffix=”” prefixOverrides=”” suffixOverrides=”” >代替< where > 、< set >

  1. <select id="selectBookByCondition" resultType="com.qf.mybatis.day2.dynamic.Book">
  2. SELECT id,name,author,publish,sort
  3. FROM t_books
  4. <trim prefix="WHERE" prefixOverrides="AND|OR"> <!-- 增加WHERE前缀,自动忽略前缀 -->
  5. <if test="id != null">
  6. and id = #{id}
  7. </if>
  8. <if test="name != null">
  9. and name = #{name}
  10. </if>
  11. <if test="author != null">
  12. and author = #{author}
  13. </if>
  14. <if test="publish != null">
  15. and publish = #{publish}
  16. </if>
  17. <if test="sort != null">
  18. and sort = #{sort}
  19. </if>
  20. </trim>
  21. </select>
  1. <update id="updateBookByCondition">
  2. UPDATE t_books
  3. <trim prefix="SET" suffixOverrides=","> <!-- 增加SET前缀,自动忽略后缀 -->
  4. <if test="name != null">
  5. name = #{name} ,
  6. </if>
  7. <if test="author != null">
  8. author = #{author} ,
  9. </if>
  10. <if test="publish != null">
  11. publish = #{publish} ,
  12. </if>
  13. <if test="sort != null">
  14. sort = #{sort}
  15. </if>
  16. </trim>
  17. WHERE id = #{id}
  18. </update>

11.6 < foreach >

  1. <delete id="deleteBookByIds">
  2. DELETE FROM t_books
  3. WHERE id IN
  4. <foreach collection="list" open="(" separator="," close=")" item="id" index="i">
  5. #{id}
  6. </foreach>
  7. </delete>
参数 描述 取值
collection 容器类型 list、array、map
open 起始符 (
close 结束符 )
separator 分隔符 ,
index 下标号 从0开始,依次递增
item 当前项 任意名称(循环中通过 #{任意名称} 表达式访问)

十二、缓存(Cache)【重点


内存中的一块存储空间,服务于某个应用程序,旨在将频繁读取的数据临时保存在内存中,便于二次快速访问。

无缓存:用户在访问相同数据时,需要发起多次对数据库的直接访问,导致产生大量IO、读写硬盘的操作,效率低下
image.png
有缓存:首次访问时,查询数据库,将数据存储到缓存中;再次访问时,直接访问缓存,减少IO、硬盘读写次数、提高效率
image.png

12.1 一级缓存

SqlSession级别的缓存,同一个SqlSession的发起多次同构查询,会将数据保存在一级缓存中。

  • 注意:无需任何配置,默认开启一级缓存。

12.2 二级缓存

SqlSessionFactory级别的缓存,同一个SqlSessionFactory构建的SqlSession发起的多次同构查询,会将数据保存在二级缓存中。

  • 注意:在sqlSession.commit()或者sqlSession.close()之后生效。

12.2.1 开启全局缓存

< settings >是MyBatis中极为重要的调整设置,他们会改变MyBatis的运行行为,其他详细配置可参考官方文档。

  1. <configuration>
  2. <properties .../>
  3. <!-- 注意书写位置 -->
  4. <settings>
  5. <setting name="cacheEnabled" value="true"/> <!-- mybaits-config.xml中开启全局缓存(默认开启) -->
  6. </settings>
  7. <typeAliases></typeAliases>
  8. </configuration>

12.2.2 指定Mapper缓存
  1. <mapper namespace="com.qf.mybatis.part2.cache.BookDao">
  2. <cache /> <!-- 指定缓存 -->
  3. <select id="selectBookByCondition" resultType="com.qf.mybatis.part2.cache.Book">
  4. SELECT * FROM t_books
  5. </select>
  6. </mapper>
  1. @Test
  2. public void testMapperCache(){
  3. SqlSession sqlSession1 = MyBatisUtils.getSession();
  4. BookDao bookDao1 = sqlSession1.getMapper(BookDao.class);
  5. bookDao1.selectBookByCondition(new Book());
  6. sqlSession1.close(); //必须关闭SqlSession才可缓存数据
  7. //--------------------
  8. SqlSession sqlSession2 = MyBatisUtils.getSession();
  9. BookDao bookDao2 = sqlSession2.getMapper(BookDao.class);
  10. bookDao2.selectBookByCondition(new Book());
  11. sqlSession2.close(); //缓存击中
  12. }

12.2.3 缓存清空并重新缓存
  1. @Test
  2. public void testMapperCache(){
  3. SqlSession sqlSession1 = MyBatisUtils.getSession();
  4. BookDao bookDao1 = sqlSession1.getMapper(BookDao.class);
  5. bookDao1.selectBookByCondition(new Book());
  6. sqlSession1.close(); //必须关闭SqlSession才可缓存数据
  7. //--------------------
  8. SqlSession sqlSession3 = MyBatisUtils.getSession();
  9. BookDao bookDao3 = sqlSession3.getMapper(BookDao.class);
  10. bookDao3.deleteBookById(102);
  11. sqlSession3.commit(); //DML成功,数据发生变化,缓存清空
  12. sqlSession3.close();
  13. //--------------------
  14. SqlSession sqlSession2 = MyBatisUtils.getSession();
  15. BookDao bookDao2 = sqlSession2.getMapper(BookDao.class);
  16. bookDao2.selectBookByCondition(new Book());
  17. sqlSession2.close(); //缓存未击中,重新查询数据库、重新缓存
  18. }

十三、Druid连接池


13.1 概念

Druid 是阿里巴巴开源平台上的一个项目,整个项目由数据库连接池、插件框架和 SQL 解析器组成。该项目主要是为了扩展 JDBC 的一些限制,可以让程序员实现一些特殊的需求,比如向密钥服务请求凭证、统计 SQL 信息、SQL 性能收集、SQL 注入检查、SQL 翻译等,程序员可以通过定制来实现自己需要的功能。

13.2 不同连接池对比

测试执行申请归还连接 1,000,000(一百万)次总耗时性能对比。

13.2.1 测试环境
环境 版本
OS OS X 10.8.2
CPU Intel i7 2GHz 4 Core
JVM Java Version 1.7.0_05

13.2.2 基准测试结果对比
JDBC-Conn Pool 1 Thread 2 threads 5 threads 10 threads 20 threads 50 threads
Druid 898 1,191 1,324 1,362 1,325 1,459
tomcat-jdbc 1,269 1,378 2,029 2,103 1,879 2,025
DBCP 2,324 5,055 5,446 5,471 5,524 5,415
BoneCP 3,738 3,150 3,194 5,681 11,018 23,125
jboss-datasource 4,377 2,988 3,680 3,980 32,708 37,742
C3P0 10,841 13,637 10,682 11,055 14,497 20,351
Proxool 16,337 16,187 18,310(Ex) 25,945 33,706(Ex) 39,501 (Ex)

13.2.3 测试结论
  • Druid 是性能最好的数据库连接池,tomcat-jdbc 和 druid 性能接近。
  • Proxool 在激烈并发时会抛异常,不适用。
  • C3P0 和 Proxool 都相当慢,影响 sql 执行效率。
  • BoneCP 性能并不优越,采用 LinkedTransferQueue 并没有能够获得性能提升。
  • 除了 bonecp,其他的在 JDK 7 上跑得比 JDK 6 上快。
  • jboss-datasource 虽然稳定,但性能很糟糕。

13.3 配置pom.xml

引入Druid依赖

  1. <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
  2. <dependency>
  3. <groupId>com.alibaba</groupId>
  4. <artifactId>druid</artifactId>
  5. <version>1.1.16</version>
  6. </dependency>

13.4 创建DruidDataSourceFactory

MyDruidDataSourceFactory并继承PooledDataSourceFactory,并替换数据源。

  1. package com.qf.mybatis.part2.utils;
  2. import com.alibaba.druid.pool.DruidDataSource;
  3. import org.apache.ibatis.datasource.pooled.PooledDataSourceFactory;
  4. public class MyDruidDataSourceFactory extends PooledDataSourceFactory {
  5. public MyDruidDataSourceFactory() {
  6. this.dataSource = new DruidDataSource();//替换数据源
  7. }
  8. }

13.5 修改mybatis-config.xml

mybatis-config.xml中连接池相关配置。

  1. <!--连接池-->
  2. <dataSource type="com.qf.mybatis.part2.utils.DruidDataSourceFactory"><!--数据源工厂-->
  3. <property name="driverClass" value="${driver}"/>
  4. <property name="jdbcUrl" value="${url}"/>
  5. <property name="username" value="${username}"/>
  6. <property name="password" value="${password}"/>
  7. </dataSource>

注意:< property name=”属性名” />属性名必须与com.alibaba.druid.pool.DruidAbstractDataSource中一致。

十四、PageHelper


14.1 概念

PageHelper是适用于MyBatis框架的一个分页插件,使用方式极为便捷,支持任何复杂的单表、多表分页查询操作。

14.2 访问与下载

官方网站:https://pagehelper.github.io/

下载地址:https://github.com/pagehelper/Mybatis-PageHelper

14.3 开发步骤

PageHelper中提供了多个分页操作的静态方法入口。

14.3.1 引入依赖

pom.xml中引入PageHelper依赖。

  1. <dependency>
  2. <groupId>com.github.pagehelper</groupId>
  3. <artifactId>pagehelper</artifactId>
  4. <version>5.1.10</version>
  5. </dependency>

14.3.2 配置MyBatis-config.xml

在MyBatis-config.xml中添加< plugins >。

  1. <configuration> <typeAliases></typeAliases>
  2. <plugins> <!-- com.github.pagehelper为PageHelper类所在包名 -->
  3. <plugin interceptor="com.github.pagehelper.PageInterceptor"></plugin>
  4. </plugins> <environments>...</environments>
  5. </configuration>

14.3.3 PageHelper应用方式

使用PageHelper提供的静态方法设置分页查询条件。

  1. @Test
  2. public void testPagehelper(){
  3. UserDao userDao = MyBatisUtils.getMapper(UserDao.class);
  4. PageHelper.startPage(1,2);//使用PageHelper设置分页条件
  5. List<User> users = userDao.selectAllUsers();
  6. for(User user : users){
  7. System.out.println(user);
  8. }
  9. }

14.4 PageInfo对象

PageInfo对象中包含了分页操作中的所有相关数据。

PageInfo结构图
MyBatis教程 - 图12

14.4.1 PageInfo应用方式

使用PageInfo保存分页查询结果。

  1. @Test
  2. public void testPageInfo(){
  3. UserDao userDao = MyBatisUtils.getMapper(UserDao.class);
  4. PageHelper.startPage(6, 2);
  5. List<User> users = userDao.selectAllUsers();
  6. PageInfo<User> pageInfo = new PageInfo<User>(users);//将分页查询的结果集保存在PageInfo对象中
  7. System.out.println(pageInfo);
  8. }

14.4.2 注意事项
  • 只有在PageHelper.startPage()方法之后的第一个查询会有执行分页。
  • 分页插件不支持带有“for update”的查询语句。
  • 分页插件不支持“嵌套查询”,由于嵌套结果方式会导致结果集被折叠,所以无法保证分页结果数量正确。。

14.4.3 分页练习

使用Servlet+JSP+MyBatis+分页插件,完成分页查询功能。

十五、补充【了解】boot


以下内容并非必备知识,了解即可。

15.1 MyBatis注解操作

通过在接口中直接添加MyBatis注解,完成CRUD。

  • 注意:接口注解定义完毕后,需将接口全限定名注册到mybatis-config.xml的< mappers >中。
  • 经验:注解模式属于硬编码到.java文件中,失去了使用配置文件外部修改的优势,可结合需求选用。
  1. <mappers>
  2. <mapper class="com.qf.mybatis.part1.annotations.UserMapper" /><!-- class="接口全限定名"-->
  3. </mappers>

15.1.1 查询
  1. public interface UserMapper {
  2. @Select("SELECT * FROM t_users WHERE id = #{id}")
  3. public User selectUserById(Integer id);
  4. @Select("SELECT * FROM t_users WHERE id = #{id} AND password = #{pwd}")
  5. public User selectUserByIdAndPwd_annotation(@Param("id") Integer id, @Param("pwd") String password);
  6. }

15.1.2 删除
  1. @Delete(value = "DELETE FROM t_users WHERE id = #{id}")
  2. public int deleteUser(Integer id);

15.1.3 修改
  1. @Update("UPDATE t_users SET name = #{name} , password = #{password} , salary = #{salary} , birthday = #{birthday} WHERE id = #{id}")
  2. public int updateUser(User user);

15.1.4 插入
  1. @Insert("INSERT INTO t_users VALUES(#{id},#{name},#{password},#{salary},#{birthday},null)")
  2. public int insertUser(User user);
  3. @Options(useGeneratedKeys = true , keyProperty = "id") // 自增key,主键为id
  4. @Insert("INSERT INTO t_users VALUES(#{id},#{name},#{password},#{salary},#{birthday},null)")
  5. public int insertUserGeneratedKeys(User user);

15.2 $符号的应用场景

${attribute} 属于字符串拼接SQL,而非预编译占位符,会有注入攻击问题,不建议在常规SQL中使用,常用于可解决动态生降序问题。

15.2.1 $符号参数绑定
  1. public List<User> selectAllUsers1(User user); // ${name} ${id} 可获取user中的属性值
  2. public List<User> selectAllUsers2(@Param("rule") String rule); //必须使用@Param否则会作为属性解析
  1. <select id="selectAllUsers1" resultType="user">
  2. SELECT * FROM t_users
  3. WHERE name = '${name}' or id = ${id} <!-- 拼接name和id,如果是字符类型需要用单引号:'${name}' -->
  4. </select>
  5. <select id="selectAllUsers2" resultType="user">
  6. SELECT * FROM t_users
  7. ORDER BY id ${rule} <!-- 拼接 asc | desc -->
  8. </select>
  1. User user = new User(....);
  2. List<User> ulist1 = userDAO.selectAllUsers1(user); //调用时传入user对象
  3. List<User> ulist2 = userDao.selectAllUsers2("desc"); //调用时传入asc | desc

15.2.2 $符号注入攻击
  1. <select id="selectUsersByKeyword" resultType="user">
  2. SELECT * FROM t_user
  3. WHERE name = '${name}' <!-- 会存在注入攻击 比如传入参数是 【String name = "tom' or '1'='1";】-->
  4. </select>
注入攻击,拼接的内容,改变了原sql语义,被攻击!
MyBatis教程 - 图13

15.3 MyBatis处理关联关系-嵌套查询【了解】

思路:查询部门信息时,及联查询所属的员工信息。

  • DepartmentDao接口中定义selectDepartmentById,并实现Mapper。
  • EmployeeDao接口中定义selectEmployeesByDeptId,并实现Mapper,
  • 当selectDepartmentById被执行时,通过< collection >调用selectEmployeesByDeptId方法,并传入条件参数。

15.3.1 主表查询

定义selectEmployeesByDeptId,并书写Mapper,实现根据部门ID查询员工信息

  1. public interface EmployeeDao {
  2. /**
  3. * 根据部门编号查询员工信息
  4. * @param did 部门编号
  5. * @return 该部门中的所有员工
  6. */
  7. public List<Employee> selectEmployeeByDeptId(@Param("did") String did);
  8. }
  1. <mapper namespace="com.qf.mybatis.part2.one2many.EmployeeDao">
  2. <!-- 根据部门编号查询所有员工 -->
  3. <select id="selectEmployeeById" resultType="employee" >
  4. SELECT id,name,salary,dept_id
  5. FROM t_employees
  6. WHERE dept_id = #{did}
  7. </select>
  8. </mapper>

15.3.2 及联调用

定义selectDepartmentById,并书写Mapper,实现根据部门ID查询部门信息,并及联查询该部门员工信息
  1. public interface DepartmentDao {
  2. /**
  3. * 查询部门信息
  4. * @param id
  5. * @return
  6. */
  7. public Department selectDepartmentById(@Param("id") String id);
  8. }
  1. <mapper namespace="com.qf.mybatis.part2.one2many.DepartmentDao">
  2. <resultMap id="departmentResultMap" type="department">
  3. <id property="id" column="id" />
  4. <result property="name" column="name" />
  5. <result property="location" column="location" />
  6. <!-- column="传入目标方法的条件参数" select="及联调用的查询目标"-->
  7. <collection property="emps" ofType="Employee" column="id"
  8. select="com.qf.mybatis.part2.one2many.EmployeeDao.selectEmployeeByDeptId" />
  9. </resultMap>
  10. <select id="selectAllDepartments" resultMap="departmentResultMap">
  11. SELECT id , name , location
  12. FROM t_departments
  13. WHERE id = #{id}
  14. </select>
  15. </mapper>

15.3.3 延迟加载

mybatis-config.xml中开启延迟加载
  1. <settings>
  2. <setting name="lazyLoadingEnabled" value="true"/> <!-- 开启延迟加载(默认false) -->
  3. </settings>
  • 注意:开启延迟加载后,如果不使用及联数据,则不会触发及联查询操作,有利于加快查询速度、节省内存资源。

十六、作业

阐述 mybatis 各个标签的作用,以及属性的作用

1、阐述什么是ORM映射?
2、什么是dtd和schema文件?
3、什么表空间和别名?
4、编写mybatis步骤
5、编写用户表、角色表、权限表的增删改查,分页和组合查询?
6、什么是缓存,mybatis一级缓存和二级缓存的作用?
7、什么是延迟加载和即时加载?