Mybatis学习记录

最近在b站关注了一个神仙up主,狂神说Java,up主讲课的风格我还是很喜欢的,听着不困,花两天把mybatis学了一下,跟着视频记录了点笔记

一、mybatis概念

1、什么是mybatis

  • MyBatis 是一款优秀的持久层框架
  • MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集的过程
  • MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的实体类 【Plain Old Java Objects,普通的 Java对象】映射成数据库中的记录。
  • MyBatis 本是apache的一个开源项目ibatis, 2010年这个项目由apache 迁移到了google code,并且改名为MyBatis 。2013年11月迁移到Github .

2、如何获得mybatis

  • Maven仓库:https://mvnrepository.com/artifact/org.mybatis/mybatis
  • GitHub : https://github.com/mybatis/mybatis-3
  • Mybatis官方文档 : http://www.mybatis.org/mybatis-3/zh/index.html

3、持久化,持久层的概念

持久化是将程序数据在持久状态和瞬时状态间转换的机制。

  • 即把数据(如内存中的对象)保存到可永久保存的存储设备中(如磁盘)。持久化的主要应用是将内存中的对象存储在数据库中,或者存储在磁盘文件中、XML数据文件中等等。
  • JDBC就是一种持久化机制。文件IO也是一种持久化机制。

什么是持久层是完成持久化工作的代码块

  • dao层 【DAO (Data Access Object) 数据访问对象】
  • 大多数情况下特别是企业级应用,数据持久化往往也就意味着将内存中的数据保存到磁盘上加以固化,而持久化的实现过程则大多通过各种关系数据库来完成。

4、为什么要用mybatis

  • 传统的jdbc操作 , 有很多重复代码块 . 比如 : 数据取出时的封装 , 数据库的建立连接等等… , 通过框架可以减少重复代码,提高开发效率 .
  • MyBatis 是一个半自动化的ORM框架 (Object Relationship Mapping) -->对象关系映射

5、使用Mybatis遇到的工程问题汇总

二、mybatis入门案例

1、搭建环境

参考:https://mybatis.org/mybatis-3/zh/getting-started.html
1、搭建数据库环境

2、使用Maven导入Mybatis相关jar包
我碰到了无法导入的情况,根据这篇解决了:maven换源方法

<!-- 导入依赖 -->
    <dependencies>
        <!-- 数据库驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.19</version>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.2</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

3、创建一个模块

  • 【先创建父工程,删除其src文件夹,配置好pom.xml后,创建子模块,这样子模块的依赖就直接用父工程的就行了】

  • 编写Mybatis核心配置文件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="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <!--& 在xml里面加 amp; 进行转义 -->
                <property name="url" value="jdbc:mysql://localhost:3306/book?useUnicode=true&amp;characterEncoding=UTF-8&amp;serverTimezone=Asia/Shanghai"/>
                <property name="username" value="root"/>
                <property name="password" value="xxxxxx"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="org/mybatis/example/BlogMapper.xml"/>
    </mappers>
</configuration>

2、编写Mybatis工具类

public class MybatisUtils {
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //1、使用Mybatis来获取SqlSessionFactory对象
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //从 SqlSessionFactory获得 SqlSession 的实例。
    //你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

3、编写代码

  • 实体类User【pojo】
  • Dao接口
public interface UserDao {
    public List<User> getUserList();
}
  • 在JDBC中是用【接口实现类】UserDaoImpl,现在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=绑定一个对应的Dao/Mapper接口-->
<mapper namespace="com.lqr.dao.UserDao">
    <select id="getUserList" resultType="com.lqr.pojo.User">
    select * from t_user
  </select>
</mapper>

4、Junit测试

1、测试代码

public class UserDaoTest {
    @Test
    public void test(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<User> userList = mapper.getUserList();
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }
}

5、测试中遇到的问题

1、【重要】配置文件没有注册
2、绑定接口错误(namespace中的包名要和接口中的包名一致)
3、方法名不对
4、返回类型不对
5、【重要】Maven静态资源过滤问题,在pom文件里插入下面的代码,并且刷新maven

<build>
    <resources>
        <resource>
            <directory>src/main/java</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
        <resource>
            <directory>src/main/resources</directory>
            <includes>
                <include>**/*.properties</include>
                <include>**/*.xml</include>
            </includes>
            <filtering>false</filtering>
        </resource>
    </resources>
</build>

6、Intellij idea 报错:Error : java 不支持发行版本5
项目编译配置使用的Java版本不对,需要检查一下项目及环境使用的Java编译版本配置。
https://blog.csdn.net/qq_22076345/article/details/82392236

6、mybatis增删改

1、编写UserMapper接口中方法
2、编写UserMapper.xml中对应的sql语句
3、测试

测试的时候要注意:增删改要提交事务

sqlSession.commit();

假设我们的实体类中,或者数据库中的表,字段,参数过多,可以考虑使用Map传参,直接在sql中取出key即可

int addUser2(Map<String,Object> map);

4、模糊查询
(1)java代码执行的时候传递通配符;

List<User> userList = mapper.getUserLike("l");

(2)在xml文件sql拼接中使用通配符,【把格式写死,预防sql注入!】

<select id="getUserLike" parameterType="String" resultType="com.lqr.pojo.User">
    select * from t_user where username like "%"#{value}"%"
</select>

三、配置解析

核心配置文件——mybatis-config.xml。其中能配置的内容如下:
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)

typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)

databaseIdProvider(数据库厂商标识)
mappers(映射器)

1、环境变量(environments)

  1. 配置MyBatis的多套运行环境,将SQL映射到多个不同的数据库上,必须指定其中一个为默认运行环境(通过default指定)
  2. 子元素节点:environment
    • dataSource 元素使用标准的 JDBC 数据源接口来配置 JDBC 连接对象的资源。
    • 数据源是必须配置的。
    • 有三种内建的数据源类型:type="[UNPOOLED|POOLED|JNDI]")
  3. 数据源也有很多第三方的实现,比如dbcp,c3p0,druid等等…

2、属性(properties)

这些属性可以在外部进行配置,并可以进行动态替换。你既可以在典型的 Java 属性文件中配置这些属性,也可以在 properties 元素的子元素中设置。

1、配置文件编写 db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/book?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
username=root
password=xxx

2、在核心配置文件中引入properties

  • 可以直接引入外部文件
  • 可以在核心配置文件中增加属性配置
  • 如果两个文件有同一字段,优先使用外部配置文件的
<properties resource="db.properties"></properties>

3、类型别名(typeAliases)

类型别名可为 Java 类型设置一个缩写名字。 它仅用于 XML 配置,意在降低冗余的全限定类名书写。 例如:
(1)typeAlias

	<typeAliases>
	    <typeAlias type="com.lqr.pojo.User" alias="user"/>
	</typeAliases>

(2)也可以指定一个包名,MyBatis 会在包名下面搜索每一个在包 domain.blog 中的 Java Bean,在没有注解的情况下,会使用 Bean 的首字母小写的非限定类名来作为它的别名。

    <typeAliases>
        <typeAlias type="com.lqr.pojo.User" alias="user"/>
        <package name="com.lqr.pojo"/>
    </typeAliases>

(3)还可以直接使用注解

@Alias("user")
public class User{
    ...
}

4、设置(settings)

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。 下表描述了设置中各项设置的含义、默认值等。

<settings>
  <setting name="cacheEnabled" value="true"/>
  <setting name="lazyLoadingEnabled" value="true"/>
  <setting name="multipleResultSetsEnabled" value="true"/>
  <setting name="useColumnLabel" value="true"/>
  <setting name="useGeneratedKeys" value="false"/>
  <setting name="autoMappingBehavior" value="PARTIAL"/>
  <setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>
  <setting name="defaultExecutorType" value="SIMPLE"/>
  <setting name="defaultStatementTimeout" value="25"/>
  <setting name="defaultFetchSize" value="100"/>
  <setting name="safeRowBoundsEnabled" value="false"/>
  <setting name="mapUnderscoreToCamelCase" value="false"/>
  <setting name="localCacheScope" value="SESSION"/>
  <setting name="jdbcTypeForNull" value="OTHER"/>
  <setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>
</settings>

其中比较重要的:

  1. mapUnderscoreToCamelCase
    是否开启驼峰命名自动映射,即从经典数据库列名 A_COLUMN 映射到经典 Java 属性名 aColumn(last_name —— lastName)。可设置为true | false

  2. logImpl
    指定 MyBatis 所用日志的具体实现,未指定时将自动查找。可设置为SLF4J | LOG4J | LOG4J2 | JDK_LOGGING | COMMONS_LOGGING | STDOUT_LOGGING | NO_LOGGING

5、其他配置

6、映射器(mappers)

MapperRegister:注册绑定我们的Mapper文件。
这些配置会告诉 MyBatis 去哪里找映射文件,剩下的细节就应该是每个 SQL 映射文件了

注意点:

  • 接口和其Mapper配置文件必须同名
  • 接口和其Mapper配置文件必须在同包下

1、方式1,resource标签,使用相对于类路径的资源引用

<!-- 使用相对于类路径的资源引用 -->
<mappers>
  <mapper resource="org/mybatis/builder/AuthorMapper.xml"/>
  <mapper resource="org/mybatis/builder/BlogMapper.xml"/>
  <mapper resource="org/mybatis/builder/PostMapper.xml"/>
</mappers>

2、方式2【推荐】,class标签,使用映射器接口实现类的完全限定类名

<!-- 使用映射器接口实现类的完全限定类名 -->
<mappers>
  <mapper class="org.mybatis.builder.AuthorMapper"/>
  <mapper class="org.mybatis.builder.BlogMapper"/>
  <mapper class="org.mybatis.builder.PostMapper"/>
</mappers>

3、方式3

<!-- 将包内的映射器接口实现全部注册为映射器 -->
<mappers>
  <package name="org.mybatis.builder"/>
</mappers>

四、声明周期和作用域

不同作用域和生命周期类是至关重要的,因为错误的使用会导致非常严重的并发问题。
下图来自:狂神说公众号
在这里插入图片描述

1、SqlSessionFactoryBuilder

  • SqlSessionFactoryBuilder 的作用在于创建 SqlSessionFactory,创建成功后,SqlSessionFactoryBuilder 就失去了作用,所以它只能存在于创建 SqlSessionFactory 的方法中,而不要让其长期存在。
  • SqlSessionFactoryBuilder 实例的最佳作用域是方法作用域(也就是局部方法变量)。

2、SqlSessionFactory

  • SqlSessionFactory 可以被看做一个数据库连接池,它的作用是创建 SqlSession 接口对象。
  • SqlSessionFactory 的生命周期存在于整个 MyBatis 的应用之中,所以一旦创建了 SqlSessionFactory,就要长期保存它,直至不再使用 MyBatis 应用。
  • 所以可以认为 SqlSessionFactory 的生命周期就等同于 MyBatis 的应用周期。
  • 由于 SqlSessionFactory 是一个对数据库的连接池,所以它占据着数据库的连接资源。如果创建多个 SqlSessionFactory,那么就存在多个数据库连接池,这样不利于对数据库资源的控制,也会导致数据库连接资源被消耗光,出现系统宕机等情况,所以尽量避免发生这样的情况。
  • 因此在一般的应用中SqlSessionFactory 作为一个单例,让它在应用中被共享。所以 SqlSessionFactory 的最佳作用域是应用作用域。

3、SqlSession

  • 如果SqlSessionFactory 相当于数据库连接池,那么 SqlSession 相当于一个数据库连接(Connection 对象)
  • 处理完整个请求后,应该关闭这条连接(SqlSession.close()),让它归还给 SqlSessionFactory,否则数据库资源就很快被耗费精光,系统就会瘫痪,所以用 try…catch…finally… 语句来保证其正确关闭。
  • SqlSession 的最佳的作用域是请求或方法作用域。
    在这里插入图片描述

五、resultMap及分页

1、resultMap

要解决的问题:属性名和字段名不一致(pojo类中字段名和数据库中字段名不一致)

比如在mapper.xml中写下

<select id="selectUserById" resultMap="UserMap">
  select id , name , pwd from user where id = #{id}
</select>

这句select * from user where id = #{id} 其实可以看做在执行select id,name,pwd from user where id = #{id}
mybatis会根据这些查询的列名(会将列名转化为小写,数据库不区分大小写) , 去对应的实体类中查找相应列名的set方法设值
假设我们pojo中密码对应是“pwd”,而数据库中对应“password”,所以查不到pwd对应的结果,所以在这里需要用到resultMap完成一个由pwd到password的映射。

<resultMap id="UserMap" type="User">
   <!-- id为主键 -->
   <id column="id" property="id"/>
   <!-- column是数据库表的列名 , property是对应实体类的属性名 -->
   <result column="name" property="name"/>
   <result column="password" property="pwd"/>
</resultMap>

2、分页

为什么要分页

查询大量数据的时候,我们往往使用分页进行查询,也就是每次处理小部分数据,这样对数据库压力就在可控范围内。

MySQL中LIMIT语法

SELECT * FROM table LIMIT stratIndex,pageSize

SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15  

#为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1:   
SELECT * FROM table LIMIT 95,-1; // 检索记录行 96-last.  

#如果只给定一个参数,它表示返回最大的记录行数目:   
SELECT * FROM table LIMIT 5; //检索前 5 个记录行  

【那么如何在Mybatis中实现分页?】
我们可以用Map传参完成分页,假设参数为stratIndex,pageSize,因此建一个Map<String,Integer>对象就ok了

1、添加接口

    //选择全部用户实现分页
    List<User> getUserByLimit(Map<String,Integer> map);

2、修改Mapper

    <!-- 结果集映射,将数据库映射为pojo -->
    <resultMap id="UserMap" type="User">
        <result column="password" property="pwd"/>
    </resultMap>

    <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select * from t_user limit #{startIndex}, #{pageSize}
    </select>

3、测试

    @Test
    public void getUserByLimit(){
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        HashMap<String, Integer> map = new HashMap<String, Integer>();
        map.put("startIndex",0);
        map.put("pageSize",2);
        List<User> userList = mapper.getUserByLimit(map);
        for (User user : userList) {
            System.out.println(user);
        }
        sqlSession.close();
    }

六、日志

Mybatis内置的日志工厂提供日志功能,具体的日志实现有以下几种工具:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j 【掌握】
  • JDK logging
  • STDOUT_LOGGING【掌握】

具体选择哪个日志实现工具由MyBatis的内置日志工厂确定。它会使用最先找到的(按上文列举的顺序查找)。如果一个都未找到,日志功能就会被禁用。

    <settings>
        <setting name="logImpl" value="LOG4J"/>
    </settings>

1、STDOUT_LOGGING

在这里插入图片描述

2、LOG4J

配置文件:
https://www.cnblogs.com/wangzhuxing/p/7753420.html

什么是LOG4J?

  • Log4j是Apache的一个开源项目
  • 通过使用Log4j,我们可以控制日志信息输送的目的地:控制台,文本,GUI组件…
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程。最令人感兴趣的就是,这些可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码。

在这里插入图片描述

简单实用:

1、导入log4j的包
2、配置文件编写

#将等级为DEBUG的日志信息输出到console和file这两个目的地,console和file的定义在下面的代码
log4j.rootLogger=DEBUG,console,file

#控制台输出的相关设置
log4j.appender.console = org.apache.log4j.ConsoleAppender
log4j.appender.console.Target = System.out
log4j.appender.console.Threshold=DEBUG
log4j.appender.console.layout = org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=[%c]-%m%n

#文件输出的相关设置
log4j.appender.file = org.apache.log4j.RollingFileAppender
log4j.appender.file.File=./log/lqr.log
log4j.appender.file.MaxFileSize=10mb
log4j.appender.file.Threshold=DEBUG
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=[%p][%d{yy-MM-dd}][%c]%m%n

#日志输出级别
log4j.logger.org.mybatis=DEBUG
log4j.logger.java.sql=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.ResultSet=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

3、setting设置日志实现

    <settings>
        <!--setting name="logImpl" value="STDOUT_LOGGING"/-->
        <setting name="logImpl" value="LOG4J"/>
    </settings>

4、在程序中使用Log4j进行输出!

    static Logger logger = Logger.getLogger(UserMapperTest.class);

    @Test
    public void testLOG4J(){
        logger.info("info:进入selectUser方法");
        logger.debug("debug:进入selectUser方法");
        logger.error("error: 进入selectUser方法");
    }

七、使用注解开发

1、面向接口编程

  • 根本原因 : 【解耦】 (可拓展 , 提高复用 , 分层开发中 , 上层不用管具体的实现 , 大家都遵守共同的标准 , 使得开发变得容易 , 规范性更好)
  • 接口从更深层次的理解,应是定义(规范,约束)与实现(名实分离的原则)的分离。

2、自动提交事务

在MybatisUtils中设置:sqlSessionFactory.openSession(true);

public class MybatisUtils {
    //提升作用域
    private static SqlSessionFactory sqlSessionFactory;
    static {
        try {
            //1、使用Mybatis来获取SqlSessionFactory对象(来自官方文档)
            String resource = "mybatis-config.xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    //2、通过SqlSessionFactor 获得 SqlSession 的实例。
    //SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。通过 SqlSession 实例来直接执行已映射的 SQL 语句
    public static SqlSession getSqlSession(){

        //设置为true就是自动提交事务
        return sqlSessionFactory.openSession(true);
    }
}

3、使用注解完成CRUD

mybatis最初配置信息是基于 XML ,映射语句(SQL)也是定义在 XML 中的。而到MyBatis 3提供了新的基于注解的配置。【但是Java 注解的的表达力和灵活性十分有限。最强大的 MyBatis 映射并不能用注解来构建】

1、我们在我们的接口中添加注解
2、注意【在mybatis的核心配置文件中注入
3、关于@Param()注解:基本类型和String需要加上,引用类型不需要加,如果只有一个基本类型可以忽略(不过建议加上)

    <!--绑定接口,使用注解-->
    <mappers>
        <mapper class="com.lqr.dao.UserMapper"/>
    </mappers>

3、代码
编写接口UserMapper ,在接口方法上添加注解。
这里有一点要注意,@Param中的参数一定要和注解中的参数统一。

public interface UserMapper {
    //查询所有结果
    @Select("select * from t_user")
    List<User> getUserList();
    
    //方法前有多个参数,都在前面加上@Param
    @Select("select * from t_user where id = #{id}")
    User getUserById(@Param("id") int id);
    //插入
    @Insert("insert into t_user(id,username,password,email) values(#{id},#{username},#{pwd},#{email})")
    int addUser(User user);
    //更新
    @Update("update t_user set username = #{username} where id = #{id}")
    int updateUser(User user);
    //删除
    @Delete("delete from t_user where id = #{uid}")
    int deleteUser(@Param("uid") int id);
}

测试:UserMapperTest.java

public class UserMapperTest {
    @Test
    public void getUserList(){
        SqlSession session = MybatisUtils.getSqlSession();
        //本质上利用了jvm的动态代理机制
        UserMapper mapper = session.getMapper(UserMapper.class);
        List<User> users = mapper.getUserList();
        for (User user : users){
            System.out.println(user);
        }
        session.close();
    }

    @Test
    public void getUserById(){
        SqlSession session = MybatisUtils.getSqlSession();
        //本质上利用了jvm的动态代理机制
        UserMapper mapper = session.getMapper(UserMapper.class);
        User user = mapper.getUserById(1);
        System.out.println(user);
        session.close();
    }

    @Test
    public void addUser(){
        SqlSession session = MybatisUtils.getSqlSession();
        //本质上利用了jvm的动态代理机制
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.addUser(new User(6,"johnson","000","098@qq.com"));
        session.close();
    }

    @Test
    public void updateUser(){
        SqlSession session = MybatisUtils.getSqlSession();
        //本质上利用了jvm的动态代理机制
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.updateUser(new User(8,"贺老板","000","098@qq.com"));
        session.close();
    }

    @Test
    public void deleteUser(){
        SqlSession session = MybatisUtils.getSqlSession();
        //本质上利用了jvm的动态代理机制
        UserMapper mapper = session.getMapper(UserMapper.class);
        mapper.deleteUser(8);
        session.close();
    }
}

3、Mybatis执行流程分析

在这里插入图片描述

八、一对多和多对一处理

第一次理解起来比较晦涩,建议结合子查询和连接查询好理解点。

1、关系表建立

【student表和teacher表】

CREATE TABLE `teacher` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO teacher(`id`, `name`) VALUES (1, '秦老师');

	
CREATE TABLE `student` (
`id` INT(10) NOT NULL,
`name` VARCHAR(30) DEFAULT NULL,
`tid` INT(10) DEFAULT NULL,
PRIMARY KEY (`id`), 
KEY `fktid` (`tid`),
CONSTRAINT `fktid` FOREIGN KEY (`tid`) REFERENCES `teacher` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('1', '小明', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('2', '小红', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('3', '小张', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('4', '小李', '1');
INSERT INTO `student` (`id`, `name`, `tid`) VALUES ('5', '小王', '1');


SELECT * FROM teacher;
SELECT * FROM student;

2、多对一的处理

1、pojo包下
【在代码中添加注解,这里用到了lombok】

@Data //GET,SET,ToString,有参,无参构造
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
   private int id;
   private String name;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
   private int id;
   private String name;
   //多个学生可以是同一个老师,即多对一
   private Teacher teacher;
}

2、在dao包下编写两个pojo类对应的mapper 接口

3、思考:
按照查询进行嵌套处理就像SQL中的子查询
按照结果进行嵌套处理就像SQL中的联表查询


1、按照查询嵌套处理

1、给StudentMapper接口增加方法

//获取所有学生及对应老师的信息
public List<Student> getStudents();

2、编写对应的StudentMapper文件

<?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.kuang.mapper.StudentMapper">
   <!--
   需求:获取所有学生及对应老师的信息
   思路:
       1. 获取所有学生的信息
       2. 根据获取的学生信息的老师ID->获取该老师的信息
       3. 思考问题,这样学生的结果集中应该包含老师,该如何处理呢,数据库中我们一般使用关联查询?
           1. 做一个结果集映射:StudentTeacher
           2. StudentTeacher结果集的类型为 Student
           3. 学生中老师的属性为teacher,对应数据库中为tid。
              多个 [1,...)学生关联一个老师=> 一对一,一对多
           4. 查看官网找到:association – 一个复杂类型的关联;使用它来处理关联查询
   -->
   <select id="getStudents" resultMap="StudentTeacher">
   	select * from student
   </select>
   
   <resultMap id="StudentTeacher" type="Student">
       <!--association关联属性 property属性名 javaType属性类型 column在多的一方的表中的列名-->
       <association property="teacher"  column="tid" javaType="Teacher" select="getTeacher"/>
   </resultMap>
   <!--
   这里传递过来的id,只有一个属性的时候,下面可以写任何值
   association中column多参数配置:
       column="{key=value,key=value}"
       其实就是键值对的形式,key是传给下个sql的取值名称,value是片段一中sql查询的字段名。
   -->
   <select id="getTeacher" resultType="teacher">
      select * from teacher where id = #{id}
   </select>
</mapper>

2、按照结果嵌套处理

1、接口方法编写

public List<Student> getStudents2();

2、编写对应的mapper文件

<!--
按查询结果嵌套处理
思路:
   1. 直接查询出结果,进行结果集的映射
-->
<select id="getStudents2" resultMap="StudentTeacher2" >
  select s.id sid, s.name sname , t.name tname
  from student s,teacher t
  where s.tid = t.id
</select>

<resultMap id="StudentTeacher2" type="Student">
   <id property="id" column="sid"/>
   <result property="name" column="sname"/>
   <!--关联对象property 关联对象在Student实体类中的属性-->
   <association property="teacher" javaType="Teacher">
       <result property="name" column="tname"/>
   </association>
</resultMap>

3、一对多的处理

1、pojo包下
在代码中添加注释

@Data
public class Student {
   private int id;
   private String name;
   private int tid;
}
@Data 
public class Teacher {
   private int id;
   private String name;
   //一个老师多个学生
   private List<Student> students;
}

1、按照查询嵌套

2、按照结果嵌套

4、小结

1、关联-association
2、集合-collection
3、所以association是用于一对一和多对一,而collection是用于一对多的关系
4、JavaType和ofType都是用来指定对象类型的

  • JavaType是用来指定pojo中属性的类型
  • ofType指定的是映射到list集合属性中pojo的类型。

九、动态SQL

动态SQL指的是根据不同的查询条件 , 生成不同的Sql语句.

根据作者名字和博客名字来查询博客,如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询

1、写接口类

List<Blog> queryBlogIf(Map map);

2、用if标签写xml

<!--需求1:
根据作者名字和博客名字来查询博客!
如果作者名字为空,那么只根据博客名字查询,反之,则根据作者名来查询
select * from blog where title = #{title} and author = #{author}
-->
<select id="queryBlogIf" parameterType="map" resultType="blog">
  select * from blog
   <where>
       <if test="title != null">
          title = #{title}
       </if>
       <if test="author != null">
          and author = #{author}
       </if>
   </where>
</select>

十、缓存

1、简介

1、什么是缓存 [ Cache ]?

  • 存在内存中的临时数据。
  • 将用户经常查询的数据放在缓存(内存)中,用户去查询数据就不用从磁盘上(关系型数据库数据文件)查询,从缓存中查询,从而提高查询效率,解决了高并发系统的性能问题。

2、为什么使用缓存?

  • 减少和数据库的交互次数,减少系统开销,提高系统效率。

3、什么样的数据能使用缓存?

  • 经常查询并且不经常改变的数据

2、mybatis缓存

MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地定制和配置缓存。缓存可以极大的提升查询效率。
MyBatis系统中默认定义了两级缓存:

  • 一级缓存和二级缓存默认情况下,只有一级缓存开启。
  • SqlSession级别的缓存,也称为本地缓存
  • 二级缓存需要手动开启和配置,他是基于namespace级别的缓存。
  • 为了提高扩展性,MyBatis定义了缓存接口Cache。我们可以通过实现Cache接口来自定义二级缓存
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值