MyBatis快速入门教程

文章目录

一、介绍

在这里插入图片描述

Spring是一个开放源代码的J2EE应用程序框架,负责管理协调 控制层和持久层。两大特性:IoC(控制反转)和AOP(面向切面编程),它有几大组件,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。

SpringMVC是一个基于mvc的框架,其实就是Spring其中一个组件。

SpringBoot简单来讲就是简化Spring应用的,不是对Spring功能上的增强,其实就是简化Spring环境的搭建以及开发的流程的。

SpringCloud是Spring给出的一套解决方案,被称为构建分布式微服务系统的“全家桶”,它并不是某一门技术,而是一系列微服务解决方案或框架的有序集合。

MyBatis 是一个基于Java的持久层框架,负责与我们数据库进行打交道的一个框架,内部实际上是封装了jdbc,让我们的dao开发起来会更简单。它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息,将接口和 Java 的 POJOs(Plain Ordinary Java Object,普通的 Java对象)映射成数据库中的记录。

MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了google code,并且改名为MyBatis。2013年11月迁移到Github。

ORM思想 对象关系映射(Object Relational Mapping)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

什么是持久层

主要就是做数据持久化

数据持久化
持久化就是将程序的数据在持久状态和瞬时状态转化的过程
内存:断电即失
让数据持久化:数据库(jdbc)、io文件持久化。
为什么需要持久化
有一些对象,不能让他丢掉。
内存太贵了
持久层
完成持久化工作的代码块
层界限十分明显

为什么要学MyBatis?

jdbc的缺陷

  1. 要创建连接,释放资源对程序的资源造成了资源浪费。
  2. SQL语句在代码中编写,造成不容易维护。
  3. 对结果集解析,要把结果进行封装,很麻烦。

这些问题都被框架简化掉了

为什么要用MyBatis?
方便程序员将数据存到数据库中
帮助
传统的JDBC代码太复杂了,简化,框架,自动化。
不用MyBatis也可以,只是学了MyBatis更容易上手
优点:
  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件。
  • 灵活:mybatis不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里。
  • sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的ORM字段关系映射。
  • 提供对象关系映射标签,支持对象关系组建维护。
  • 提供xml标签,支持编写动态sql。

二、如何获得MyBatis?

maven仓库:https://mvnrepository.com/artifact/org.mybatis/mybatis

<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.6</version>
</dependency>

GitHub:https://github.com/search?q=mybatis
中文文档:https://mybatis.org/mybatis-3/zh/index.html

三、第一个Mybatis程序

创建一个Maven工程
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
PS:设置本地仓库这里,由于我用的IDEA 是2020.1版本,本地仓库只能是默认的,不然就会报错找不到包。

数据库

数据库名叫mydb,里面有一张用户表user

CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `username` varchar(30) NOT NULL,
  `password` varchar(30) NOT NULL,
  `sex` char(2) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8;

ALTER TABLE `user`
  ADD PRIMARY KEY (`id`);

ALTER TABLE `user`
  MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;

INSERT INTO `user` (`id`, `username`, `password`, `sex`) VALUES
(1, '小意', '123456', '女'),
(2, '清风', '1234567', '男'),
(3, '微泫', '123123', '男');

导入maven依赖

pom.xml , scope作用域记得删掉,junit-jupiter这里不用也可以删掉
在这里插入图片描述

<!--  mybatis  -->
<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>3.5.6</version>
</dependency>
<!--  mysql驱动  -->
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <version>5.1.46</version>
</dependency>

bean 实体类

src.main.java.com.qibu.bean
User 类

package com.qibu.bean;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String sex;

    public User(){

    }

    public User(Integer id, String username, String password, String sex) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.sex = sex;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

dao持久层

main.java.com.qibu.dao
它不需要写实现类,我们只需要写接口就行了,IUserDao接口,I表示接口的意思。

package com.qibu.dao;

import com.qibu.bean.User;

import java.util.List;

public interface IUserDao {
    /**
     * 查询所有用户信息
     */
    public List<User> findAllUser();
}

resources

编写对应的映射文件

我们接口最终肯定还是要实现它,怎么实现?不是搞一个类实现它,我们需要在这个main包下面新建一个文件夹resources,这个项目跟普通的JavaWeb项目不一样,它要求的是你的所有的一些配置文件、配置信息就应该放到resources下面。我们在resources下新建一个包com.qibu.dao,然后新建一个实现类,这个实现类,它不是一个类,它是一个file文件后缀是xml,新建IUserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--DTD约束,用来约束xml文档。规定xml文档中元素的名称,子元素的名称及顺序,元素的属性等等。-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- 上面不写就报错 -->
<!-- namespace命名空间可以任选命名,但最好要定义一定规则,便于后继的使用,
例如我这个实现的是IUserDao接口,所以我们必须写这个包的全路径名com.qibu.dao.IUserDao
包的全限定名  包名+类名
-->
<mapper namespace="com.qibu.dao.IUserDao">
    <!--  实现查询所有用户信息的方法  -->
	<!--  id是实现方法的名字,resultType 返回的结果类型  -->
    <select id="findAllUser" resultType="com.qibu.bean.User">
        select * from user
    </select>
</mapper>

mybatis主配置文件

写在resources下,我们新建一个文件叫mybatis-config.xml(名字可以随便取),注意DTD约束跟上面写的IUserDao.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">
            <!--事务管理类型主要有jdbc和managed,前者依赖于数据源获得的连接,后者依赖于容器 -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <!-- 如果数据库设置为UTF-8,则URL参数连接需要添加?useUnicode=true&amp;characterEncoding=UTF-8,如下 -->
                <property name="url"
                          value="jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="密码"/>
            </dataSource>
        </environment>
    </environments>

    <!--  告知mybatis映射配置的位置  -->
    <mappers>
    <!--   resource数据源     -->
        <mapper resource="com/qibu/dao/IUserDao.xml"/>
    </mappers>


</configuration>

测试类

main.java.com.qibu.test
新建一个测试类MyBatisTest,注意是import org.apache.ibatis.io.Resources;

package com.qibu.test;

import com.qibu.bean.User;
import com.qibu.dao.IUserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Test;

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

public class MyBatisTest {
    @Test
    public void testfindAllUser() throws IOException {
        //读取mybatis主配置文件
        InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        SqlSessionFactory  sessionFactory= builder.build(is);
        //获得session对象
        SqlSession session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        IUserDao dao = session.getMapper(IUserDao.class);
        //使用代理对象来执行查询所有的方法
        List<User> users = dao.findAllUser();
        for (User user : users) {
            System.out.println(user.toString());
        }
        //释放资源
        session.close();
        is.close();

    }
}

PS:等到我们MyBatis全部学完之后,学完Spring之后你会发现这里面所有的代码所有的操作都不需要你做了,就是这上面的代码都不需要你做,你只需要一行代码 dao.findAllUser() 就可以查出来了,全部简化掉。

在这里插入图片描述

运行,结果:
运行成功

运行遇到报错Could not find resource com/qibu/dao/IUserDao.xml

告诉你没有找到com/qibu/dao/IUserDao.xml

Could not find resource com/qibu/dao/IUserDao.xml

可能是IDEA的bug吧,我的IDEA版本是2020.1,我们在resources下创建目录的时候不能直接com.qibu.dao。应该新建com,新建qibu,新建dao。

在这里插入图片描述

上面用的是xml的方式,接下来是用注解的方式,会非常的简单

使用注解的方式

用注解IUserDao.xml文件都不用了,删掉IUserDao.xml文件,com.qibu.dao的IUserDao写注解 @Select("select * from user")

在这里插入图片描述

 <mapper class="com.qibu.dao.IUserDao"></mapper>

在这里插入图片描述


我们先用xml的方式,我们先撤回上面注释删掉的操作

在这里插入图片描述
在这里插入图片描述


查看日志

我们可以给mybatis框架添加日志管理的功能,mybatis内置有日志工厂,日志工厂默认交给以下其中一种工具做代理:

  • SLF4J
  • Apache Commons Logging
  • Log4j 2
  • Log4j
  • JDK logging

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

1. 指定日志代理工具是LOG4J

可做可不做
mybatis-config.xml

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

在这里插入图片描述

2. 引入LOG4J工具包

pom.xml

<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.12</version>
</dependency>

3. 设置配置文件

设置配置文件,也就是它的输出位置
resources目录下放log4j.properties文件,这些都不用我们去写,复制粘贴拿来用就好了。

# 设置全局的日志输出级别是debug   debug < info < warn < error < fatal
# 设置全局的输出源是stdout-输出到控制台
log4j.rootLogger=debug,stdout
# My logging configuration...
log4j.logger.cn.jbit.mybatisdemo=DEBUG
# 设置stdout输出源的相关信息
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%5p %d %C: %m%n
log4j.logger.org.apache.ibatis=DEBUG
## log4j.logger.org.apache.jdbc.SimpleDataSource=DEBUG
log4j.logger.org.apache.ibatis.jdbc.ScriptRunner=DEBUG
## log4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapclientDelegate=DEBUG
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG

4. 运行

运行测试类MyBatisTest
在这里插入图片描述
PooledDataSource forcefully closed/removed all connections. 数据连接池准备就绪了。
Opening JDBC Connection 已经打开了JDBC的连接。
Created connection 893504292.创建了一个连接对象。这就说明了其实mybatis内部是有一个连接池的。
Setting autocommit to false on JDBC Connection 我们设置自动提交为false 。
Total: 3 查到的结果集为3条
Resetting autocommit to true on JDBC Connection 设置自动提交为true,数据库增删改每次一定要去提交事务。
Closing JDBC Connection关闭了这个连接。
Returned connection 893504292 to pool.返回这个连接给连接池,编号是893504292 。

log4j没效果

可能是因为我创建resources是直接点
在这里插入图片描述

解决办法:Ctrl + Shift + Alt + S 或者 File -> Project Structure
将我们的resources标记取消然后重新标记,重启IDEA,运行就好了。
在这里插入图片描述

只要一设置代理就报错The setting logImpl is not known. Make sure you spelled it correctly (case sensitive).

在这里插入图片描述
在这里插入图片描述

报错信息:

org.apache.ibatis.exceptions.PersistenceException: 
### Error building SqlSession.
### The error may exist in SQL Mapper Configuration
### Cause: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: The setting logImpl is not known.  Make sure you spelled it correctly (case sensitive).

	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:23)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:79)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:63)
	at com.qibu.test.MyBatisTest.init(MyBatisTest.java:33)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.apache.ibatis.builder.BuilderException: Error parsing SQL Mapper Configuration. Cause: org.apache.ibatis.builder.BuilderException: The setting logImpl is not known.  Make sure you spelled it correctly (case sensitive).
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:105)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parse(XMLConfigBuilder.java:88)
	at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:77)
	... 25 more
Caused by: org.apache.ibatis.builder.BuilderException: The setting logImpl is not known.  Make sure you spelled it correctly (case sensitive).
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.settingsElement(XMLConfigBuilder.java:192)
	at org.apache.ibatis.builder.xml.XMLConfigBuilder.parseConfiguration(XMLConfigBuilder.java:99)
	... 27 more


java.lang.NullPointerException
	at com.qibu.test.MyBatisTest.destory(MyBatisTest.java:43)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:33)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)


Process finished with exit code -1

MyBatis 的版本换成3.2.7或以上,此问题解决,原因是MyBatis 3.1.1 -jar 还没有 logImpl 这个设置。
在这里插入图片描述

通过id查找用户

IUserDao

package com.qibu.dao;

import com.qibu.bean.User;
//import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface IUserDao {
    /**
     * 查询所有用户信息
     */
//    @Select("select * from user")
    public List<User> findAllUser();

    /**
     * 通过id来查询用户信息
     */
    public User findById(Integer userId);
}

parameterType 将会传入这条语句的参数的类全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler)推断出具体传入语句的参数,默认值为未设置(unset)。

resources.com.qibu.dao.IUserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.qibu.dao.IUserDao">
    <!--  实现查询所有用户信息的方法  -->
    <!--  id是实现方法的名字,resultType 返回的结果类型  -->
    <select id="findAllUser" resultType="com.qibu.bean.User">
        select * from user
    </select>

    <!--  通过id查询用户   -->
    <select id="findById" resultType="com.qibu.bean.User" parameterType="int">
        select * from user where id=#{userid}
    </select>
    
</mapper>

resultType是用来指定结果集的类型,支持基本数据类型和实体类类型
parameterType 用于指定参数类型(基本数据类型int或者它的包装类Integer)
#{}相当于占位符 ,相当于原来JDBC部分所学的?
#{userId} 具体的数据是由#{}的内容决定的,写什么名字都不是重点
由于parameterType指定的数据类型是基本数据类型,所以#{}此处可以随便填写

main.java.com.qibu.test.MyBatisTest
改造了一下

package com.qibu.test;

import com.qibu.bean.User;
import com.qibu.dao.IUserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class MyBatisTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder;
    private SqlSessionFactory sessionFactory;
    private SqlSession session;
    private IUserDao dao;


    @Before    //在测试方法执行之前执行
    public void init() throws IOException {
        //读取mybatis主配置文件
        is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象
        builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        sessionFactory = builder.build(is);
        //获得session对象
        session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        dao = session.getMapper(IUserDao.class);
    }

    @After //表示在测试方法执行之后执行
    public void destory() throws IOException {
        //提交事务  增删改后一定要控制事物的提交
        session.commit();
        //释放资源
        session.close();
        is.close();
    }

    @Test
    public void testFindAllUser() {
        //使用代理对象来执行查询所有的方法、
        List<User> users = dao.findAllUser();
        for (User user : users) {
            System.out.println(user.toString());
        }
    }

    @Test
    public void testFindById() throws IOException {
        User user = dao.findById(1);
        System.out.println(user.toString());
    }
}

@Before //在测试方法执行之前执行
@After //表示在测试方法执行之后执行

session.commit(); 提交事务。增删改之后一定要控制事务的提交,如果没有提交事务,那么增删改是没有效果的。但是就有一个问题,如果你是查询你还提交事务干什么呢?这个后面学到Spring的时候,它会帮我们控制管理它,Spring在中间做管家,帮我们管理东西。

增(添加一个用户)

main.java.com.qibu.dao.IUserDao

 /**
  * 添加一个用户
  * 返回受影响的行数
  */
 public int saveUser(User user);

resources.com.qibu.dao.IUserDao.xml

<!-- 添加一个用户 -->
<insert id="saveUser" parameterType="com.qibu.bean.User">
    insert into user(username,password,sex) values (#{username},#{password},#{sex})
</insert>

parameterType属性代表的参数类型,因为我们要传入一个类的对象,所以类型就要写类的全名称
#{}里面的内容 由于保存方法的参数是User对象,此处内容要写User对象的属性名称
类的属性名称区分大小写
因为他遵循的是OGNL表达式

OGNL表达式(Object-Graph Navigation Language) 是apache提供的一种表达式语言, 对象图像导航语言
它会通过这一个属性username就可以找到User对象,然后找到User对象之后就可以找到User对象里面的这个username属性,找到这个属性username的时候,它就会去找这个属性username的get方法把值取出来,它就是这么去做的。

main.java.com.qibu.test.MyBatisTest

@Test
public void testSaveUser() throws IOException {
    int result = dao.saveUser(new User(0, "意", "202020", "女"));
    System.out.println(result + "行受影响");
}

结果:1行受影响

<selectKey>

很多时候,假如我们新增一个用户之后需要返回用户的id编号

配置保存时获取插入的id
select last_insert_id();得到刚新增进去记录的主键id值,只适用于自增主键
keyProperty 将查询到主键值设置到指定的对象的哪个属性
resultType 指定select last_insert_id();查询的结果类型
keyColumn数据库里面的哪一个字段

resources.com.qibu.dao.IUserDao.xml

<insert id="saveUser" parameterType="com.qibu.bean.User">
    <selectKey  keyColumn="id"  keyProperty="id" resultType="int">
        select last_insert_id();
    </selectKey>
    insert into user(username,password,sex) values (#{username},#{password},#{sex})
</insert>

因为字段名字是一样的,可以省略keyColumn=“id”

<insert id="saveUser" parameterType="com.qibu.bean.User">
    <selectKey  keyProperty="id" resultType="int">
        select last_insert_id();
    </selectKey>
    insert into user(username,password,sex) values (#{username},#{password},#{sex})
</insert>

main.java.com.qibu.test.MyBatisTest

@Test
public void testSaveUser() throws IOException {
    User user = new User();
    user.setUsername("xy");
    user.setPassword("123456");
    user.setSex("男");
    dao.saveUser(user);
    System.out.println("插入数据的主键: "+user.getId());
}

运行

在这里插入图片描述

改(修改用户信息)

main.java.com.qibu.dao.IUserDao

/* 修改用户信息 */
public int updateUser(User user);

resources.com.qibu.dao.IUserDao.xml

<update id="updateUser" parameterType="com.qibu.bean.User">
    update user set username=#{username},password=#{password},sex=#{sex} where id=#{id}
</update>

main.java.com.qibu.test.MyBatisTest

@Test
public void testUpdateUser() throws IOException {
    User user = dao.findById(2);
    user.setUsername("玉米排骨汤");
    user.setPassword("666666");
    user.setSex("女");
    int result = dao.updateUser(user);
    System.out.println(result + "行受影响");
}

运行testUpdateUser()
结果:1行受影响

删(删除一个用户)

main.java.com.qibu.dao.IUserDao

/**
 * 删除一个用户
 * @param id
 * @return
 */
public int deleteUser(Integer id);

resources.com.qibu.dao.IUserDao.xml

<delete id="deleteUser" parameterType="java.lang.Integer">
    delete  from user where id=#{id}
</delete>

main.java.com.qibu.test.MyBatisTest

@Test
public void testDeleteUser() throws IOException {
    int result = dao.deleteUser(12);
    System.out.println(result + "行受影响");
}

运行testDeleteUser()
结果:1行受影响

模糊查询

main.java.com.qibu.dao.IUserDao

/**
 * 模糊查询
 * @param username
 * @return
 */
public List<User> findByUserName(String username);

resources.com.qibu.dao.IUserDao.xml

<select id="findByUserName" parameterType="String" resultType="com.qibu.bean.User">
    select * from user where username like #{username}
</select>

main.java.com.qibu.test.MyBatisTest

@Test
public void testFindByUserName() {
    //使用代理对象来执行查询所有的方法、
    List<User> users = dao.findByUserName("%排骨汤%");
    for (User user : users) {
        System.out.println(user.toString());
    }
}

运行testFindByUserName()

这里还可以另一种写法

<select id="findByUserName" parameterType="String" resultType="com.qibu.bean.User">
    select * from user where username like '%${value}%'
</select>

在原来的 #{} 占位符,改成了${value},注意如果是用模糊查询的写法,那么${value}的写法是固定的,不能写成其他名字

@Test
public void testFindByUserName() {
    //使用代理对象来执行查询所有的方法、
    List<User> users = dao.findByUserName("排骨汤");//注意这里不用%%
    for (User user : users) {
        System.out.println(user.toString());
    }
}

#{} 和 ${} 的区别

  1. #{}表示一个占位符号 相当于 jdbc中的 ? 符号,#{} 可以实现向prepareStatement中的预处理语句中设置参数值,自动进行java类型和jdbc类型之间的转换
  2. #{} 可以防止sql注入(安全),${}方式无法防止sql注入
  3. #{}可以接收pojo类型(实体类型)或者基本数据类型,${} 将我们的参数内容不进行jdbc的转换
  4. 如果传递简单类型值,#{} 括号中可以是value或者其他名称。
  5. 通过${}可以将内容拼接在sql语句中且不进行类型转换,${}可以接受简单数据类型或者pojo属性值, 如果传递简单类型值,${}扩种只能是value

#{}方式能够很大程度防止sql注入(安全),${}方式无法防止sql注入,在JDBC能使用占位符的地方,最好优先使用#{},在JDBC不支持使用占位符的地方,就只能使用${},典型情况就是 动态参数。

举个例子,比如 有两张表,分别是xxx_a 和 xxx_b .如果需要在查询语句中 动态指定表名,就只能使用${}

<select>
      select * from xxx_${value}
<select>

再比如MyBatis 排序时使用order by 动态参数时,此时也只能使用${}

<select>
       select * from user order by ${value}
</select>

查询总记录数

main.java.com.qibu.dao.IUserDao

/**
 * 查询总记录数
 * @return
 */
public int findTotal();

resources.com.qibu.dao.IUserDao.xml

<select id="findTotal" resultType="int">
    select count(*) from user
</select>

main.java.com.qibu.test.MyBatisTest

@Test
public void testFindTotal() {
    int total = dao.findTotal();
    System.out.println("总记录数" + total);
}

当数据库名和类的属性名不匹配时

假如我数据库的字段名是这样的:
在这里插入图片描述
我们随便运行一个查询,返回回来的是null
在这里插入图片描述
当实体类的属性跟数据库里的字段名不一致的时候,没有办法对我们的结果进行自动化封装。解决办法:我们可以用resultMap 。


resultMap建立查询的列名和实体类属性名称不一致时建立对应关系,从而实现封装。

在select标签中使用resultMap属性指定引用即可。

同时resultMap属性可以实现查询结果映射为复杂类型的pojo。比如实现一对一或者一对多。

resources.com.qibu.dao.IUserDao.xml

建立User实体与数据的映射关系

<resultMap id="UserMap" type="com.qibu.bean.User">
    <id property="id" column="user_id"></id>
    <result property="username" column="user_name"></result>
    <result property="password" column="user_password"></result>
    <result property="sex" column="user_sex"></result>
</resultMap>

<select id="findAllUser" resultMap="UserMap">
    select * from user
</select>

在这里插入图片描述
在这里插入图片描述

resultMap标签

id属性: 给一个唯一的标识,是给查询的select标签的resultMap属性来引用的。
type属性: 指定实体类的全类名。

resultMap 标签可以建立查询的列名和实体类的属性名称不一致时,建立对应关系,从而实现封装。

select标签中使用resultMap属性指定引用即可。

同时resultMap属性可以实现查询结果映射为复杂类型的pojo。比如实现一对一或者一对多。

id标签

id标签用于指定主键字段,只有主键能用,其他的字段只能用result标签
property属性: 用于指定实体类属性名称
column属性: 用于指定数据库表中的列名

result标签

用于指定非主键字段


上面的是MyBatis基于Mapper(代理对象)的执行方式。还有另外一种方式,我们不用代理dao,使用传统的dao层开发,了解即可

给实体类设置别名

我们每次在映射文件中,每次写实体类都要写很长一段,例如com.qibu.bean.User,这时候我们可以取一个别名。

type 实体类
alias 别名

mybatis-config.xml

<typeAliases>
    <typeAlias type="com.qibu.bean.User" alias="User"></typeAlias>
</typeAliases>

这样参数就可以直接用别名了

IUserDao.xml

在这里插入图片描述

PS: 自己运行MyBatisTest文件测试就好了

批量定义<package>

有一个实体类就有一个 dao 一个映射文件xxx.xml,假如我们有50个实体类,我们要写50个 <mapper resource=“xxx.xml”/> 50个<typeAlias>吗?他有一个批量定义。

<package name=“父文件夹位置”/>

批量别名定义

mybatis-config.xml

<typeAliases>
   <package name="com.qibu.bean"/>
</typeAliases>

批量别名定义,扫描整个包下的所有的类,别名为类名,并且使用别名的时候,首字母大小写都可以,不敏感。

批量扫描映射文件

mybatis-config.xml

<mappers>
	<!--  第一种,设置相对路径  resource数据源 -->
	<!-- <mapper resource="com/qibu/dao/IUserDao.xml"/> -->
	<!-- 第二种,使用 mapper 接口类路径-->
	<!--  <mapper class="com.qibu.dao.IUserDao"></mapper> -->
	<!--第三种,批量扫描-->
   <package name="com.qibu.dao"></package>
</mappers>

四、使用传统的dao层开发(了解即可)

前面讲的 dao = session.getMapper(IUserDao.class); getMapper是代理Dao的开发方式,接口代理的开发方式, 现在的话主流的就是这种方式。

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
注意:保存的位置(Location)不是mybatis_day01目录下。

新建完之后又要搭框架,复制mybatis_day01的代码,dao目录下新建一个impl目录,新建UserDaoImpl实现类去实现这个接口。

在这里插入图片描述

package com.qibu.dao;

import com.qibu.bean.User;

import java.util.List;

public interface IUserDao {

    public List<User> findAllUser();

    public User findById(Integer userId);

    public int saveUser(User user);

    public int updateUser(User user);

    public int deleteUser(Integer id);

}

PS:这里就只写几个方法吧,不全部复制了

首先我们要拿到一个SqlSessionFactory,我们要通过构造函数去获得SqlSessionFactory,因为我们要拿到SqlSessionFactory之后我们才可以去获得session,然后才可以调用里面的方法。再Session.selectList(),这跟我们之前的方式不一样,这个是调用Session里面的API方法,selectList意思就是查询所有,然后这里面它要定位到哪一个方法?com.qibu.dao.IUserDao.findAllUser这个方法。然后再 Session.close();这里需要关闭的,然后它查完之后就会自动的返回这个结果给我。

单个查询叫selectOne()

这种方式比较繁琐, 所以我们只是作为了解, 但是你要知道它有这几种方式的

package com.qibu.dao.impl;

import com.qibu.bean.User;
import com.qibu.dao.IUserDao;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;

import java.util.List;

public class UserDaoImpl implements IUserDao {

    private SqlSessionFactory factory;

    public UserDaoImpl(SqlSessionFactory factory){
     this.factory=factory;
    }

    @Override
    public List<User> findAllUser() {
        SqlSession sqlSession = factory.openSession();
        //查询所有
        List<User> users = sqlSession.selectList("com.qibu.dao.IUserDao.findAllUser");//IUserDao的方法名findAllUser
        sqlSession.close();
        return users;
    }

    @Override
    public User findById(Integer userId) {
        SqlSession sqlSession = factory.openSession();
        User user = sqlSession.selectOne("com.qibu.dao.IUserDao.findById", userId);
        sqlSession.close();
        return user;
    }

    @Override
    public int saveUser(User user) {
        SqlSession sqlSession = factory.openSession();
        int result = sqlSession.insert("com.qibu.dao.IUserDao.saveUser", user);
        sqlSession.commit();
        sqlSession.close();
        return result;
    }

    @Override
    public int updateUser(User user) {
        SqlSession sqlSession = factory.openSession();
        int result = sqlSession.update("com.qibu.dao.IUserDao.updateUser", user);
        sqlSession.commit();
        sqlSession.close();
        return result;
    }

    @Override
    public int deleteUser(Integer id) {
        SqlSession sqlSession = factory.openSession();
        int result = sqlSession.delete("com.qibu.dao.IUserDao.deleteUser", id);
        sqlSession.commit();
        sqlSession.close();
        return result;
    }
}

IUserDao.xml代码一定要写对,这里直接把之前写的IUserDao.xml复制过来,测试类复制过来运行。

相当于在原来代理方式的基础上还要再写一个实现类,太麻烦了。

这才是一个完整的项目结构

在这里插入图片描述

五、mybatis连接池

mybatis 中也有连接池技术,但是它采用的是自己的连接池技术。

在我们配置数据源的时候,就实现了mybatis连接池配置了,mybatis-config.xml

Mybatis 将它自己的数据源(dataSource) 分为三类:
POOLED 使用连接池的数据源(用的最多)
UNPOOLED 不使用连接池的数据源
JNDI 使用 JNDI 技术实现的数据源, 每个服务器对应的连接池技术都不一样,比如tomcat服务器使用的dpcp连接池。意思是我们这一个是使用 JNDI 技术实现数据库的连接池。

在这里插入图片描述mybatis在初始化的时候,他会根据dataSource里面type属性来创建相应的数据类型的数据源,数据库连接池就是说当我们真正的要用的时候它才会去获取并创立连接打开这个连接,用完之后就会把这个连接归还给连接池,我们在前面的日志也看到了。

六、动态sql语句

根据用户信息查询用户列表,我也不知道是通过性别还是名字。

main.java.com.qibu.dao.IUserDao

/**
 * 根据有用户信息,查询用户列表
 * @param user
 * @return
 */
public List<User> findByUser(User user);

<if>标签

test属性中写的是对象的属性名,使用的是OGNL表达式的写法
另外where 1=1 的作用是true

resources.com.qibu.dao.IUserDao.xml

<select id="findByUser" resultMap="UserMap" parameterType="User">
    select * from user where 1=1
    <if test="username!=null and username!=''">
        and user_name like #{username}
    </if>
    <if test="sex!=null and sex!=''">
        and user_sex like #{sex}
    </if>
</select>

main.java.com.qibu.test.MyBatisTest

@Test
public void testFindByUser() throws IOException {
    User user =new User();
    user.setUsername("%泫%");
	user.setSex("男");
    List<User> users = dao.findByUser(user);
    for (User user2 : users) {
        System.out.println(user2);
    }
}

<where>标签

简化where 1=1,if条件如果有就会去给他拼接一个where关键字

<select id="findByUser" resultMap="UserMap" parameterType="User">
    select * from user
    <where>
        <if test="username!=null and username!=''">
            and user_name like #{username}
        </if>
        <if test="sex!=null and sex!=''">
            and user_sex like #{sex}
        </if>
    </where>
</select>

<sql>标签和<include>

<sql>用于封装sql语句,<include>来调用

<sql id="queryAll">
    select * from user
</sql>

<select id="findAllUser" resultMap="UserMap">
   <include refid="queryAll"/>
</select>

<foreach>

foreach 标签用于遍历集合
collection 属性 就是你你要循环的集合
open 属性 代表语句的开始部分
close 属性 代表结束的部分
item 属性 代表遍历集合的每个元素,叫啥名字无所谓
separator 属性 代表分隔符

假如我想找id为1、3、5的用户

main.java.com.qibu.bean下新建一个QueryVo类,目的是为了封装几个数据的

package com.qibu.bean;

import java.util.List;

//目的是为了封装几个数据的
public class QueryVo {
    private List<Integer> ids;

    public List<Integer> getIds() {
        return ids;
    }

    public void setIds(List<Integer> ids) {
        this.ids = ids;
    }
}

main.java.com.qibu.dao.IUserDao

/**
 * 根据id集合查询用户信息
 * @param vo
 * @return
 */
public List<User> findIds(QueryVo vo);

resources.com.qibu.dao.IUserDao.xml

select * from user WHERE user_id in ( 1 , 3 , 5 )

<select id="findIds" resultMap="UserMap" parameterType="QueryVo">
    <include refid="queryAll"/>
    <where>
        <if test="ids!=null and ids.size>0 ">
            <foreach collection="ids" open="user_id in (" close=")" item="id" separator=",">
                #{id}
            </foreach>
        </if>
    </where>
</select>

main.java.com.qibu.test.MyBatisTest

@Test
public void testFindIds() throws IOException {
    QueryVo vo = new QueryVo();
    List<Integer> ids = new ArrayList<>();
    ids.add(1);
    ids.add(3);
    ids.add(5);
    vo.setIds(ids);
    List<User> users = dao.findIds(vo);
    for (User user : users) {
        System.out.println(user);
    }
}

七、多表查询

数据库

新增一个课程表。

在这里插入图片描述

create table course
(
    course_id   int auto_increment,
    course_name varchar(30) null,
    user_id     int         null,
    constraint course_pk
        primary key (course_id)
)comment '课程表';

insert into course(course_name, user_id)
values ("英语课",1),
    ("高等数学",1),
    ("区块链开发基础",2),
    ("C语言程序设计",2);
多个选课记录对应一个用户
对于 选课记录,关联,多个选课记录关联一个用户【多对一】
对于 用户,集合,一个用户有多个选课记录【一对多】

多对一

实现查询选课记录时,也要关联查询账户所对应的用户信息

隐式内连接
select c.*, u.user_name,u.user_sex from course c, user u WHERE u.user_id = c.user_id;
显式内连接
select c.*, u.user_name,u.user_sex from course c left join user u on c.user_id = u.user_id;

第一种方式

另外的去扩展了一个pojo类(CourseUser)作为输出类型,然后让它(CourseUser)去继承了(Course),然后在sql语句里面查询了所有的查询结果集的所有字段,这种方式相对来说是比较简单的,我们在开发的时候这种方式用的也比较多。

实体类

新建Course课程记录类

package com.qibu.bean;

public class Course {
    private  Integer courseid;
    private  String coursename;
    private Integer userid;

    public Integer getCourseid() {
        return courseid;
    }

    public void setCourseid(Integer courseid) {
        this.courseid = courseid;
    }

    public String getCoursename() {
        return coursename;
    }

    public void setCoursename(String coursename) {
        this.coursename = coursename;
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }
    
}

新建CourseUser类是用户表和课程表组合,同时包含用户信息以及课程信息

package com.qibu.bean;

//同时包含用户信息以及课程信息
public class CourseUser extends Course{
    private String username;
    private String usersex;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getUsersex() {
        return usersex;
    }

    public void setUsersex(String usersex) {
        this.usersex = usersex;
    }

    @Override
    public String toString() {
        return "课程号:"+this.getCourseid()+",课程名:"+this.getCoursename()+",用户名:"+this.getUsername();
    }
}

dao

ICourseDao

package com.qibu.dao;

import com.qibu.bean.CourseUser;

import java.util.List;

public interface ICourseDao {
    //查询所有课程,同时获得课程的信息以及用户名称和性别
    List<CourseUser> findAll();
}

映射文件

ICourseDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.qibu.dao.ICourseDao">
    <resultMap id="CourseUserMap" type="CourseUser">
        <id property="courseid" column="course_id"></id>
        <result property="coursename" column="course_name"></result>
        <result property="username" column="user_name"></result>
        <result property="usersex" column="user_sex"></result>
        <result property="userid" column="user_id"></result>
    </resultMap>

    <select id="findAll" resultMap="CourseUserMap">
        select c.*, u.user_name,u.user_sex from course c, user u WHERE u.user_id = c.user_id
    </select>
</mapper>
测试类

MyBatisTest2

package com.qibu.test;

import com.qibu.bean.CourseUser;
import com.qibu.dao.ICourseDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class MyBatisTest2 {
    private InputStream is;
    private SqlSessionFactoryBuilder builder;
    private SqlSessionFactory sessionFactory;
    private SqlSession session;
    private ICourseDao dao;


    @Before    //在测试方法执行之前执行
    public void init() throws IOException {
        //读取mybatis主配置文件
        is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象 
        builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        sessionFactory = builder.build(is);
        //获得session对象
        session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        dao = session.getMapper(ICourseDao.class);
    }

    @After //表示在测试方法执行之后执行
    public void destory() throws IOException {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        is.close();
    }

    @Test
    public void testFindAll(){
        List<CourseUser> list = dao.findAll();
        for (CourseUser courseUser : list) {
            System.out.println(courseUser);
        }
    }
    
}

在这里插入图片描述

第二种方式(常用)
实体类

我们在Course类中加入User类对象作为Course类的一个属性

package com.qibu.bean;

public class Course {
    private  Integer courseid;
    private  String coursename;
    private Integer userid;
    
    // 在Course类中加入User类对象作为Course类的一个属性
    private  User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    public Integer getCourseid() {
        return courseid;
    }

    public void setCourseid(Integer courseid) {
        this.courseid = courseid;
    }

    public String getCoursename() {
        return coursename;
    }

    public void setCoursename(String coursename) {
        this.coursename = coursename;
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseid=" + courseid +
                ", coursename='" + coursename + '\'' +
                ", userid=" + userid +
                ", user=" + user +
                '}';
    }
}

新建User类

package com.qibu.bean;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String sex;

    public User() {

    }

    public User(Integer id, String username, String password, String sex) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.sex = sex;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }
}

dao

ICourseDao

//方式二
List<Course> findAllCourse();
映射文件(association 一对一关联)

跟方式一是同一条sql语句

resultMap建立关系

association标签

property 属性名字
javaType 类型

<resultMap id="CourseMap" type="Course">
    <id property="courseid" column="course_id"></id>
    <result property="coursename" column="course_name"></result>
    <result property="userid" column="user_id"></result>
    <!--    一对一的配置    -->
    <association property="user" javaType="User">
        <id property="id" column="user_id"></id>
        <result property="username" column="user_name"></result>
        <result property="password" column="user_password"></result>
        <result property="sex" column="user_sex"></result>
    </association>
</resultMap>
<select id="findAllCourse" resultMap="CourseMap">
    select c.*, u.user_name, u.user_sex
    from course c,
         user u
    WHERE u.user_id = c.user_id
</select>
测试类

MyBatisTest2

@Test
public void testFindAllCourse(){
    List<Course> list = dao.findAllCourse();
    for (Course course : list) {
        System.out.println(course);
    }
}

在这里插入图片描述

一对多

实现查询用户信息的同时,以及用户的所有选课记录。

collection标签 用于建立一对多中集合属性的对应关系;
property=“” 关联查询的结果集存储在User对象的那个属性上;
ofType=“” 关联的结果集中的对象类型,List集合中的对象的类型,此处可以使用别名或者全类名。简单来说就是用于指定集合元素的数据类型。

select u.*,c.course_id,c.course_name from user u left join course c on c.user_id = u.user_id;

实体类

我们在User类中加入Course类对象集合作为User类的一个属性

package com.qibu.bean;

import java.util.List;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String sex;
    //查询用户信息同时关联所有选课记录
    private List<Course> courses;

    public User() {

    }

    public User(Integer id, String username, String password, String sex) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.sex = sex;
    }
    public List<Course> getCourses() {
        return courses;
    }

    public void setCourses(List<Course> courses) {
        this.courses = courses;
    }


    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", sex='" + sex + '\'' +
                ", courses='" + courses + '\'' +
                '}';
    }
}

Course 类

package com.qibu.bean;

public class Course {
    private  Integer courseid;
    private  String coursename;
    private Integer userid;
//    private  User user;
//
//    public User getUser() {
//        return user;
//    }
//
//    public void setUser(User user) {
//        this.user = user;
//    }

    public Integer getCourseid() {
        return courseid;
    }

    public void setCourseid(Integer courseid) {
        this.courseid = courseid;
    }

    public String getCoursename() {
        return coursename;
    }

    public void setCoursename(String coursename) {
        this.coursename = coursename;
    }

    public Integer getUserid() {
        return userid;
    }

    public void setUserid(Integer userid) {
        this.userid = userid;
    }

    @Override
    public String toString() {
        return "Course{" +
                "courseid=" + courseid +
                ", coursename='" + coursename + '\'' +
                ", userid=" + userid +
//                ", user=" + user +
                '}';
    }
}

dao

IUserDao

package com.qibu.dao;

import com.qibu.bean.User;

import java.util.List;

public interface IUserDao {
    public List<User> findAllUser();

}
映射文件(collection 一对多关系)

IUserDao.xml

collection标签用于建立一对多中集合属性的对应关系

property=“courses” 关联查询的结果集存储在User对象的那个属性上

ofType=“Course” 关联的结果集中的对象类型 List集合中对象的类型,此处可以使用别名或者全类名

ofType用于指定集合元素的数据类型

<?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.qibu.dao.IUserDao">
        <resultMap id="UserMap" type="User">
            <id property="id" column="user_id"></id>
            <result property="username" column="user_name"></result>
            <result property="password" column="user_password"></result>
            <result property="sex" column="user_sex"></result>
            <!--    配置一对多        -->
            <collection property="courses" ofType="Course">
                <id property="courseid" column="course_id"></id>
                <result property="coursename" column="course_name"></result>
                <result property="userid" column="user_id"></result>
            </collection>
        </resultMap>
        <!-- 配置查询所有操作 -->
        <select id="findAllUser" resultMap="UserMap">
            select u.*,c.course_id,c.course_name from user u left join course c on c.user_id = u.user_id;
        </select>
</mapper>
测试类

UserDaoTest

package com.qibu.test;

import com.qibu.bean.User;
import com.qibu.dao.IUserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class UserDaoTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder;
    private SqlSessionFactory sessionFactory;
    private SqlSession session;
    private IUserDao dao;


    @Before    //在测试方法执行之前执行
    public void init() throws IOException {
        //读取mybatis主配置文件
        is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象
        builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        sessionFactory = builder.build(is);
        //获得session对象
        session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        dao = session.getMapper(IUserDao.class);
    }

    @After //表示在测试方法执行之后执行
    public void destory() throws IOException {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        is.close();
    }
    @Test
    public void testFindAll(){
        List<User> users = dao.findAllUser();
        User user =users.get(0);
            System.out.println(user);


    }
}

在这里插入图片描述


多对多

多对多其实就是两个一对多

在生活当中哪些属于多对多?比如说 老师和学生,老师可以上很多班的课,学生可以上很多老师的课;一个班级可以有多个老师去上课,老师可以去多个班级上课; 一个人有很多角色,一个角色有很多人。


为了方便好看,我们新建一个项目,弄好结构,复制log4j.properties(要就要,不要就无所谓了)、mybatis-config.xml、pom.xml 该复制的复制

在这里插入图片描述

在这里插入图片描述


数据库表
# 角色
DROP TABLE IF EXISTS role;
create table role
(
    role_id   int auto_increment comment 'ID' primary key,
    role_name varchar(20)
);
insert into role(role_name)
values ("Java架构师"),
       ("前端工程师"),
       ("运维工程师"),
       ("Java开发工程师");

# 用户
DROP TABLE IF EXISTS user;
create table user
(
    user_id   int auto_increment comment 'userID' primary key,
    user_name varchar(20),
    birthday  datetime,
    sex       varchar(1),
    address   varchar(100)
);
insert into user(user_name, birthday, sex, address)
values ("杰克", "2001-07-21", "男", "长沙天心区"),
       ("晚风", "2002-01-11", "女", "长沙雨花区"),
       ("小梦", "2003-09-02", "女", "长沙嘉新区"),
       ("露思", "2000-07-01", "女", "长沙天心区"),
       ("麦克", "2001-05-03", "男", "长沙开福区"),
       ("小华", "2000-08-10", "男", "长沙岳麓区"),
       ("小李", "2002-06-13", "男", "长沙天心区"),
       ("龙龙", "1999-02-01", "男", "望城区");
       
# 角色用户中间表
DROP TABLE IF EXISTS user_role;
create table user_role
(
    user_id int,
    role_id int
);
insert into user_role
values (1, 1),
       (1, 4),
       (2, 1),
       (2, 2),
       (2, 3),
       (3, 1),
       (4, 1),
       (5, 2),
       (6, 2),
       (7, 2),
       (8, 1),
       (8, 2);

select u.*, r.role_id, r.role_name
from role r
         left join user_role ur on r.role_id = ur.role_id
         left join user u on u.user_id = ur.user_id;
多对多操作-查询角色获取角色下所属用户信息
bean(实体类)

Role角色实体类

package com.qibu.bean;

import java.util.List;

//角色
public class Role {
    private Integer roleId;
    private String roleName;

    //多对多的关系映射  一个角色可以赋予多个用户
    private List<User> users;

    public Role() {

    }

    public Role(Integer roleId, String roleName) {
        this.roleId = roleId;
        this.roleName = roleName;
    }

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    public Integer getRoleId() {
        return roleId;
    }

    public void setRoleId(Integer roleId) {
        this.roleId = roleId;
    }

    public String getRoleName() {
        return roleName;
    }

    public void setRoleName(String roleName) {
        this.roleName = roleName;
    }

    @Override
    public String toString() {
        return "Role{" +
                "roleId=" + roleId +
                ", roleName='" + roleName + '\'' +
                ", users=" + users +
                '}';
    }
}

User用户实体类

package com.qibu.bean;

import java.util.List;

// 用户和角色  多对多
// 用户表
public class User {
    /* 从用户去出发,一个用户可以有多个角色,所以用户到角色的关系也是一对多关系,
       这样我们就可以认为我们把User和这个Role多对多关系,把它拆分成两个一对多的关系来实现。
        然后我们是不是再把那个代码再重新写一遍就可以了.
     */
    private Integer user_id;
    private String user_name;
    private String birthday;//搞个日期也行
    private String sex;
    private String address;

    // 实现 User 到 Role 的一对多查询
//    private List<Role> roles;

    public User() {

    }

//    public User(Integer user_id, String user_name, String birthday, String sex, String address, List<Role> roles) {
//        this.user_id = user_id;
//        this.user_name = user_name;
//        this.birthday = birthday;
//        this.sex = sex;
//        this.address = address;
//        this.roles = roles;
//    }

    public Integer getUser_id() {
        return user_id;
    }

    public void setUser_id(Integer user_id) {
        this.user_id = user_id;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

//    public List<Role> getRoles() {
//        return roles;
//    }
//
//    public void setRoles(List<Role> roles) {
//        this.roles = roles;
//    }

    @Override
    public String toString() {
        return "User{" +
                "user_id=" + user_id +
                ", user_name='" + user_name + '\'' +
                ", birthday='" + birthday + '\'' +
                ", sex=" + sex +
                ", address='" + address + '\'' +
//                ", roles=" + roles +
                '}';
    }
}

dao

IRoleDao

package com.qibu.dao;

import com.qibu.bean.Role;

import java.util.List;

public interface IRoleDao {
    //    查询所有角色
    public List<Role> findAll();

}
映射文件

IRoleDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace 命名空间   包的全限定名     包名+类名  -->
<mapper namespace="com.qibu.dao.IRoleDao">
    <!--  定义一个Role表的resultMap  -->
    <resultMap id="roleMap" type="Role">
        <id column="role_id" property="roleId"></id>
        <result column="role_name" property="roleName"></result>
        <collection property="users" ofType="User">
            <id column="user_id" property="user_id"></id>
            <result column="user_name" property="user_name"></result>
            <result column="birthday" property="birthday"></result>
            <result column="sex" property="sex"></result>
            <result column="address" property="address"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="roleMap">
        select u.*,r.role_id,r.role_name from role r left join user_role ur on r.role_id = ur.role_id
        left join user u on u.user_id = ur.user_id;
    </select>
</mapper>
测试类
package com.qibu.test;

import com.qibu.bean.Role;
import com.qibu.dao.IRoleDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class RoleDaoTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder;
    private SqlSessionFactory sessionFactory;
    private SqlSession session;
    private IRoleDao dao;


    @Before    //在测试方法执行之前执行
    public void init() throws IOException {
        //读取mybatis主配置文件
        is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象
        builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        sessionFactory = builder.build(is);
        //获得session对象
        session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        dao = session.getMapper(IRoleDao.class);
    }

    @After //表示在测试方法执行之后执行
    public void destory() throws IOException {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        is.close();
    }
    @Test
    public void testFindAll(){
        List<Role> roles = dao.findAll();
       for (Role role : roles){
           System.out.println(role);
//           System.out.println(role.getUsers());
       }

    }
}

在这里插入图片描述

多对多操作-查询用户获取用户所包含的角色信息

从用户去出发,一个用户可以有多个角色,所以用户到角色的关系也是一对多关系,这样我们就可以认为我们把User和这个Role多对多关系,把它拆分成两个一对多的关系来实现。然后我们是不是再把那个代码再重新写一遍就可以了。

bean(实体类)

User用户类

package com.qibu.bean;

import java.util.List;

// 用户和角色  多对多
// 用户表
public class User {
    /* 从用户去出发,一个用户可以有多个角色,所以用户到角色的关系也是一对多关系,
       这样我们就可以认为我们把User和这个Role多对多关系,把它拆分成两个一对多的关系来实现。
        然后我们是不是再把那个代码再重新写一遍就可以了.
     */
    private Integer user_id;
    private String user_name;
    private String birthday;//搞个日期也行
    private String sex;
    private String address;

    // 实现 User 到 Role 的一对多查询
    private List<Role> roles;

    public User() {

    }

    public User(Integer user_id, String user_name, String birthday, String sex, String address, List<Role> roles) {
        this.user_id = user_id;
        this.user_name = user_name;
        this.birthday = birthday;
        this.sex = sex;
        this.address = address;
        this.roles = roles;
    }

    public Integer getUser_id() {
        return user_id;
    }

    public void setUser_id(Integer user_id) {
        this.user_id = user_id;
    }

    public String getUser_name() {
        return user_name;
    }

    public void setUser_name(String user_name) {
        this.user_name = user_name;
    }

    public String getBirthday() {
        return birthday;
    }

    public void setBirthday(String birthday) {
        this.birthday = birthday;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    @Override
    public String toString() {
        return "User{" +
                "user_id=" + user_id +
                ", user_name='" + user_name + '\'' +
                ", birthday='" + birthday + '\'' +
                ", sex=" + sex +
                ", address='" + address + '\'' +
                ", roles=" + roles +
                '}';
    }
}
dao

IUserDao

package com.qibu.dao;

import com.qibu.bean.User;
import java.util.List;

public interface IUserDao {
    //    查询所有用户
    public List<User> findAll();
}
映射文件

IUserDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace 命名空间   包的全限定名     包名+类名  -->
<mapper namespace="com.qibu.dao.IUserDao">
    <!--  定义一个Role表的resultMap  -->
    <resultMap id="userMap" type="User">
        <id column="user_id" property="user_id"></id>
        <result column="user_name" property="user_name"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <collection property="roles" ofType="Role">
            <id column="role_id" property="roleId"></id>
            <result column="role_name" property="roleName"></result>
        </collection>
    </resultMap>
    <select id="findAll" resultMap="userMap">
        select u.*,r.role_id,r.role_name from role r left join user_role ur on r.role_id = ur.role_id
                                                     left join user u on u.user_id = ur.user_id;
    </select>
</mapper>
测试类
package com.qibu.test;

import com.qibu.bean.User;
import com.qibu.dao.IRoleDao;
import com.qibu.dao.IUserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class UserDaoTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder;
    private SqlSessionFactory sessionFactory;
    private SqlSession session;
    private IUserDao dao;


    @Before    //在测试方法执行之前执行
    public void init() throws IOException {
        //读取mybatis主配置文件
        is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象
        builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        sessionFactory = builder.build(is);
        //获得session对象
        session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        dao = session.getMapper(IUserDao.class);
    }

    @After //表示在测试方法执行之后执行
    public void destory() throws IOException {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        is.close();
    }
    @Test
    public void testFindAll(){
        List<User> users = dao.findAll();
       for (User user : users){
           System.out.println(user);
           System.out.println(user.getRoles());
       }

    }
}

在这里插入图片描述

java.io.IOException: Could not find resource mybatis-config.xml

首先,因为target文件夹下没有生成mybatis-config.xml文件,所以执行代码就会报错,由于target下没有生成mybatis-config.xml文件,代码运行就会报错:Could not find resource mybatis-config.xml

在这里插入图片描述

百度了很多,最后发现pom.xml文件中多了一行代码,将这行删掉或者注释,刷新maven再重新运行即可。

在这里插入图片描述

原因分析:因为在项目里建了一个子模块,而原本的项目变成了父模块,父模块默认的打打包方式为<packaging>pom</packaging>,所以添加子模块之后pom.xml中多出了这一行代码。

<packaging></packaging>这个标签是什么意思呢?她是设置项目打包方式的一个标签。

maven中的packaging标签

项目的打包类型:pom、jar、war,packing默认是jar类型

  • <packaging>pom</packaging>父类型都为pom类型

  • <packaging>jar</packaging> 内部调用或者是作服务使用

  • <packaging>war</packaging> 需要部署的项目

而pom是最简单的打包类型。不像一个jar,sar,或者ear,它生成的构件只是它本身。没有代码需要测试或者编译,也没有资源需要处理。**也就是说使用pom打包方式就不会去处理xml文件。**原本是没有packaging这一行代码的,默认的打包方式就是jar,所以将这行代码删掉或者改为<packaging>jar</packaging>都是可以的。

在这里插入图片描述

java: 程序包com.qibu.dao不存在(xxx程序包不存在)

maven包管理的clean方法

1、把项目的MavenProject打开

2、点击clean,再点击run,即可运行

**分析其原因:**之前点击了clean,再点击install,生成了错误的target,清除target之后重新生成就ok了

在这里插入图片描述

八、缓存

像我们很多这种持久层框架的话,他都有这个缓存策略,通过缓存策略来减少数据库的IO次数和查询次数,从而来提高我们数据库的效率。在mybatis中有两种缓存,一个叫一级缓存,一个叫二级缓存。

一级缓存

一级缓存就是处于我们SqlSession里面

怎么去证明一级缓存呢?

我们打开练习一对多的那个案例里面来(随便哪个方法都可以),我们怎么去证明一级缓存呢?

一级缓存是存在我们SqlSession当中,也就是说只要有SqlSession就可以去拿到一级缓存

在这里插入图片描述

首先我们要看日志,你看这个地方我们已经发送了sql语句了,去查了一次了,查了一次然后去打印出来了,结果我们第二次再查的时候,发现一个问题没有,他直接打印出来了,他有没有去数据库里面查?没有。这是怎么回事嘞?这就是刚刚提到的,在我们的SqlSession对象他是相当于说我们在代码中发起了两次查询,但是他只是到数据库里面去查了一次,这就意味着我们mybatis他提供给我们的这一个一级缓存就是这个叫SqlSession他已经起效了,所以导致我们第二次再去查的时候他就没有到数据库去查,而是从缓存里面去查的,所以这就是我们的一级缓存。

一级缓存就是处于SqlSession范围之内,当我们去调用SqlSession的修改添加删除commit或者close之后,他就会把我们这些缓存给它清除掉。

在这里插入图片描述

记住一点就行了,如果SqlSession去执行了commit操作(增删改),清空SqlSession中的一级缓存,这样的话做的目的就是为了让缓存中的最新的数据避免 脏读

所以市面上所说的这种缓存技术其实都是这个原理,比如redis、cache,他都是这个原理,mybatis本身自己就具备了一级缓存,这就是缓存的概念。

就是说当我们第一次先去查,查完之后就相当于这个数据没有找到这个数据,那么他就会去数据库里面去查,查到之后怎么做,他就会把这个数据保存到缓存里面,当我第二次去查的时候怎么做,先到缓存里面去找,缓存里面如果找不到才会再去数据库里面去查。

在这里插入图片描述

如图所示,session.clearCache();清除缓存,清除之后就会查两次!!!

在这里插入图片描述

二级缓存

二级缓存是更高级的缓存,叫文件级别缓存。

开启二级缓存

<!--  开启二级缓存支持   -->
<setting name="cacheEnabled" value="true"/>

需要在mybatis的主配置文件当中要来开启一个二级缓存

在这里插入图片描述

配置相应的sql映射文件(xxx.xml)

useCache=“true”,表示针对我这个方法你帮我去使用二级缓存,每次查询最新的数据你就可以把它设置为false(禁用二级缓存),true表示开启二级缓存。

<cache eviction="LRU" flushInterval="6000" readOnly="false" size="1024"></cache>
或者
<cache/>

这个更高级的配置创建了一个 FIFO 缓存,并每隔 60 秒刷新,存数结果对象或列表的 512 个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会 导致冲突。

  • 可用的收回策略有:

    • LRU – 最近最少使用的:移除最长时间不被使用的对象。
    • FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
    • SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
    • WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。
    • 默认的是 LRU。
  • flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒 形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。

  • size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的 可用内存资源数目。默认值是 1024。

  • readOnly(只读)属性可以被设置为 true 或 false。只读的缓存会给所有调用者返回缓 存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存 会返回缓存对象的拷贝(通过序列化) 。这会慢一些,但是安全,因此默认是 false。

<select ... flushCache="false" useCache="true"/>
<insert ... flushCache="true"/>
<update ... flushCache="true"/>
<delete ... flushCache="true"/>
  • 第一种情况:当sql语句为select语句的情况下:

    • flushCache默认值是false,表示任何时候语句被调用,都不会去清空本地缓存和二级缓存。
    • useCache默认值是true,表示会将本条语句的结果进行二级缓存。
    • 如果没有去配置flushCache、useCache,那么默认是启用缓存的
  • 第二种情况:当sql语句为insert、update、delete语句的情况下:

    • flushCache默认值为true,表示任何时候语句被调用,都会导致本地缓存和二级缓存被清空。
    • 在insert、update、delete语句没有useCache属性。
    • flushCache 将其设置为 true,任何时候只要语句被调用,都会导致本地缓存和二级缓存都会被清空,默认值:false。
    • useCache 将其设置为 true,将会导致本条语句的结果被二级缓存,默认值:对 select 元素为 true。
 <select id="findAllUser" resultMap="UserMap" useCache="true">

在这里插入图片描述

Bean实现Serializable接口

注意:刚刚我们说过,二级缓存是文件级别缓存,所以他会把我们查询出来的对象 进行序列化,写到你的一个文件当中,但是序列化的过程当中 ,他发现 你的类没有序列化,所以你在这里你要怎么做?implements Serializable

在这里插入图片描述
在这里插入图片描述

写测试类

	@Test
    public void testFindAll(){
        SqlSession  sqlSession1 = sessionFactory.openSession();
        IUserDao IUserDao1= sqlSession1.getMapper(IUserDao.class);

        List<User> users = IUserDao1.findAllUser();
        User user =users.get(0);
        System.out.println("第一次查询"+user);

        // 查一遍把一级缓存给它关了
        sqlSession1.close();//一级缓存消失

        SqlSession  sqlSession2 = sessionFactory.openSession();
        IUserDao IUserDao2= sqlSession2.getMapper(IUserDao.class);
        List<User> users2 = IUserDao2.findAllUser();
        User user2 =users2.get(0);
        System.out.println("第二次查询"+user2);
        sqlSession2.close();
        // 再查一遍又把一级缓存给它关了

        /* 我们来看他会不会发起两次请求。
        如果没有发起两次查询,也就意味着二级缓存生效了!!!*/
    }

我们来看有没有生效,我把SqlSession一级缓存清空掉,我再查一次,如果我第二次没有重新再查就说明我的二级缓存已经在帮我进行缓存了。

在这里插入图片描述

第二次是哪里取的?二级缓存,因为一级缓存已经被我清掉了。

在这里插入图片描述

九、mybatis注解开发

为了方便好看,创建一个新项目

mybatis的常用注解说明

@Insert: 新增
@Update: 修改
@Delete: 删除
@Select: 
@SelectKey
	keyColumn 	表示插入数据以后,要返回的内容在数据表中对应的字段名称
	keyProperty 实体类中对应的属性名称
	statement   ="select last_insert_id()" 表示定义的查询的子语句
	resultType 	表示返回主键的类型,要传一个字节码对象Integer.class,不能int
	before		false表示在插入之前执行,由于主键自增,所以你要写成false
@Result: 实现结果集封装
	id =true表示是一个主键
	column 字段是哪一个,大小写不敏感
	property 属性 区分大小写
@Results: 可以配合@Result一起使用, 封装多个结果集,你这么去理解 相当于你在xml定义了一个<resultMap></resultMap>标签
	id 取名字
@ResultMap: 实现引入@Results定义的封装
@One: 一对一封装
@Many: 一对多结果集封装 ,多对多Many to Many,我们会把Many to Many看成双向的 一对多 
@SelectProvider: 实现动态SQL映射
@CacheNameSpace: 注解实现二级缓存

数据库

新建一张表

# 用户表
DROP TABLE IF EXISTS user;
create table user
(
    user_id   int auto_increment comment 'userID' primary key,
    user_name varchar(20),
    birthday  datetime,
    sex       varchar(1),
    address   varchar(100)
);
insert into user(user_name, birthday, sex, address)
values ("杰克", "2001-07-21", "男", "长沙天心区"),
       ("晚风", "2002-01-11", "女", "长沙雨花区"),
       ("小梦", "2003-09-02", "女", "长沙嘉新区"),
       ("露思", "2000-07-01", "女", "长沙天心区"),
       ("麦克", "2001-05-03", "男", "长沙开福区"),
       ("小华", "2000-08-10", "男", "长沙岳麓区"),
       ("小李", "2002-06-13", "男", "长沙天心区"),
       ("龙龙", "1999-02-01", "男", "望城区");

bean实体类

package com.qibu.bean;

import java.util.List;

// 用户表
public class User {
    private Integer userId;//故意让属性和数据库表中的字段不一致
    private String userName;
    private String userBirthday;//搞个日期也行
    private String userSex;
    private String userAddress;

    public User() {
    }

    public User(Integer userId, String userName, String userBirthday, String userSex, String userAddress) {
        //  有参构造有没有都无所谓
        this.userId = userId;
        this.userName = userName;
        this.userBirthday = userBirthday;
        this.userSex = userSex;
        this.userAddress = userAddress;
    }

    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", userBirthday='" + userBirthday + '\'' +
                ", userSex='" + userSex + '\'' +
                ", userAddress='" + userAddress + '\'' +
                '}';
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getUserBirthday() {
        return userBirthday;
    }

    public void setUserBirthday(String userBirthday) {
        this.userBirthday = userBirthday;
    }

    public String getUserSex() {
        return userSex;
    }

    public void setUserSex(String userSex) {
        this.userSex = userSex;
    }

    public String getUserAddress() {
        return userAddress;
    }

    public void setUserAddress(String userAddress) {
        this.userAddress = userAddress;
    }
}

dao

package com.qibu.dao;

import com.qibu.bean.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

public interface IUserDao {
    //    查询所有用户
    //    不需要写映射文件了
    @Select("select * from user ")
    @Results(id = "userMap", value = {
            @Result(id = true, column="user_id", property="userId"),
            @Result(column="user_name", property="userName"),
            @Result(column="birthday", property="userBirthday"),
            @Result(column="sex", property="userSex"),
            @Result(column="address", property="userAddress")
    })
    public List<User> findAllUser();//可以省略public

    @Select("select * from user where user_id = #{uid}")
    @ResultMap("userMap")
    User findUserByUId(Integer uId);

    @Insert("insert into user(user_name,birthday,sex,address) values(#{userName},#{userBirthday},#{userSex},#{userAddress})")
    @SelectKey(keyProperty = "userId", keyColumn = "user_id", resultType = Integer.class, before = false, statement = "select last_insert_id()")
    int saveUser(User user);

    @Update("update user set user_name=#{userName},  birthday=#{userBirthday},  sex=#{userSex}, address=#{userAddress} where user_id=#{userId}")
    int updateUser(User user);

    @Delete("delete from user where user_id=#{uid}")
    int deleteUser(Integer uId);

    @Select("select count(*) from user ")
    int findTotal();

    @Select("select * from user where user_name like #{userName} ")
    @ResultMap("userMap")
    List<User> findByName(String userName);
}

主配置文件

mybatis-config.xml

配置properties文件

这里面是有一个加载顺序的,你要先加载它再加载他

<?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>
    <!--    配置properties文件,有加载顺序的,不放前面就报错  -->
    <properties resource="jdbc.properties"></properties>

    <settings>
        <!--  开启二级缓存   -->
        <setting name="cacheEnabled" value="true"/>

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

<!--		不用了		 -->
<!--    &lt;!&ndash;   给实体类定义别名     &ndash;&gt;-->
<!--    <typeAliases>-->
<!--        <package name="com.com.qibu.bean"/>-->
<!--    </typeAliases>-->

    <!--可以设置多个运行环境,满足不同需要,例如 开发、测试、生产环境上有不同一配置 -->
    <environments default="mysql">
        <environment id="mysql">
            <!--事务管理类型主要有jdbc和managed,前者依赖于数据源获得的连接,后者依赖于容器 -->
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="${jdbc.driver}"/>
                <!-- 如果数据库设置为UTF-8,则URL参数连接需要添加?useUnicode=true&amp;characterEncoding=UTF-8,如下 -->
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

<!--    &lt;!&ndash;可以设置多个运行环境,满足不同需要,例如 开发、测试、生产环境上有不同一配置 &ndash;&gt;-->
<!--    <environments default="mysql">-->
<!--        <environment id="mysql">-->
<!--            &lt;!&ndash;事务管理类型主要有jdbc和managed,前者依赖于数据源获得的连接,后者依赖于容器 &ndash;&gt;-->
<!--            <transactionManager type="JDBC"/>-->
<!--            <dataSource type="POOLED">-->
<!--                <property name="driver" value="com.mysql.jdbc.Driver"/>-->
<!--                &lt;!&ndash; 如果数据库设置为UTF-8,则URL参数连接需要添加?useUnicode=true&amp;characterEncoding=UTF-8,如下 &ndash;&gt;-->
<!--                <property name="url"-->
<!--                          value="jdbc:mysql://localhost:3306/mydb?useUnicode=true&amp;characterEncoding=UTF-8"/>-->
<!--                <property name="username" value="root"/>-->
<!--                <property name="password" value="123456"/>-->
<!--            </dataSource>-->
<!--        </environment>-->
<!--    </environments>-->

    <!--  告知mybatis映射配置的位置  -->
    <mappers>
        <!--  第一种,设置相对路径  resource数据源 -->
        <!-- <mapper resource="com/qibu/dao/IUserDao.xml"/> -->
        <!--第三种,批量扫描-->
        <!--  <package name="com.qibu.dao"></package>-->

        <!-- 第二种,使用 mapper 接口类路径-->
        <!--  <mapper class="com.qibu.dao.IUserDao"></mapper> -->

        <!--   使用package标签指定dao接口所在的包的位置     -->
        <package  name="com.qibu.dao" ></package>
    </mappers>
</configuration>

在这里插入图片描述
在这里插入图片描述

jdbc.properties
useSSL=true

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb?useSSL=true&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

useSSL=false

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/mydb?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC
jdbc.username=root
jdbc.password=123456

测试类

package com.qibu.test;

import com.qibu.bean.User;
import com.qibu.dao.IUserDao;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

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

public class UserDaoTest {
    private InputStream is;
    private SqlSessionFactoryBuilder builder;
    private SqlSessionFactory sessionFactory;
    private SqlSession session;
    private IUserDao dao;


    @Before    //在测试方法执行之前执行
    public void init() throws IOException {
        //读取mybatis主配置文件
        is = Resources.getResourceAsStream("mybatis-config.xml");
        //创建SqlSessionFactory的构建者对象
        builder = new SqlSessionFactoryBuilder();
        //通过构建者对象创建工厂对象
        sessionFactory = builder.build(is);
        //获得session对象
        session = sessionFactory.openSession();
        //使用session创建dao接口的代理对象
        dao = session.getMapper(IUserDao.class);
    }

    @After //表示在测试方法执行之后执行
    public void destory() throws IOException {
        //提交事务
        session.commit();
        //释放资源
        session.close();
        is.close();
    }
    @Test
    public void testFindAll(){
        List<User> users =dao.findAllUser();
        for (User user : users) {
            System.out.println(user.toString());
        }
    }



    @Test
    public void testfindUserByUId(){
        User user = dao.findUserByUId(3);
        System.out.println(user);
    }

    @Test
    public void testSaveUser(){
        User user = new User();
        user.setUserName("晚意");
        user.setUserBirthday("2004-03-1");
        user.setUserSex("女");
        user.setUserAddress("广州白云区");
        dao.saveUser(user);
        System.out.println("新增后的主键id=>" + user.getUserId());
    }
    @Test
    public void testupdateUser(){
        User user = dao.findUserByUId(6);
        user.setUserName("晚风2");
        user.setUserBirthday("1999-01-01");
        user.setUserSex("女");
        int result=dao.updateUser(user);
        System.out.println("受影响的行数"+result);

        System.out.println("修改之后查一下");
        User user2 = dao.findUserByUId(6);
        System.out.println(user2);
    }
    @Test
    public void testdeleteUser(){
        int result=dao.deleteUser(8);
        System.out.println("删除: 受影响的行数"+result);
        testFindAll();
    }

    @Test
    public void testfindTotal(){
        int result = dao.findTotal();
        System.out.println("总共有"+result+"条");
    }
    @Test
    public void testfindByName(){
        List<User> users =dao.findByName("%晚%");
        for (User user : users) {
            System.out.println(user);
        }
    }


}


在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

报错SSL

报错:不建议在没有服务器身份验证的情况下建立 SSL 连接。 根据MySQL 5.5.45+、5.6.26+ 和 5.7.6+ 要求,如果未设置显式选项,则必须默认建立 SSL 连接。 为了符合不使用 SSL 的现有应用程序,verifyServerCertificate 属性设置为“false”。您需要通过设置 useSSL=false 来显式禁用 SSL,或者设置 useSSL=true 并为服务器证书验证提供信任库。

最省事的方法是修改数据库连接信息,在链接之后加上“useSSL=false”,直接禁用SSL连接方式。jdbc.properties文件

org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 990 milliseconds ago.  The last packet sent successfully to the server was 973 milliseconds ago.
### The error may exist in com/qibu/dao/IUserDao.java (best guess)
### The error may involve com.qibu.dao.IUserDao.findAllUser
### The error occurred while executing a query
### Cause: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 990 milliseconds ago.  The last packet sent successfully to the server was 973 milliseconds ago.

	at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:149)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140)
	at org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:80)
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:152)
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:85)
	at com.sun.proxy.$Proxy18.findAllUser(Unknown Source)
	at com.qibu.test.UserDaoTest.testFindAll(UserDaoTest.java:49)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:497)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
	at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: com.mysql.jdbc.exceptions.jdbc4.CommunicationsException: Communications link failure

The last packet successfully received from the server was 990 milliseconds ago.  The last packet sent successfully to the server was 973 milliseconds ago.
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
	at com.mysql.jdbc.SQLError.createCommunicationsException(SQLError.java:990)
	at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:201)
	at com.mysql.jdbc.MysqlIO.negotiateSSLConnection(MysqlIO.java:4912)
	at com.mysql.jdbc.MysqlIO.proceedHandshakeWithPluggableAuthentication(MysqlIO.java:1663)
	at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1224)
	at com.mysql.jdbc.ConnectionImpl.coreConnect(ConnectionImpl.java:2190)
	at com.mysql.jdbc.ConnectionImpl.connectOneTryOnly(ConnectionImpl.java:2221)
	at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2016)
	at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:776)
	at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:47)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:422)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:425)
	at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:386)
	at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:330)
	at java.sql.DriverManager.getConnection(DriverManager.java:664)
	at java.sql.DriverManager.getConnection(DriverManager.java:208)
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.doGetConnection(UnpooledDataSource.java:224)
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.doGetConnection(UnpooledDataSource.java:219)
	at org.apache.ibatis.datasource.unpooled.UnpooledDataSource.getConnection(UnpooledDataSource.java:95)
	at org.apache.ibatis.datasource.pooled.PooledDataSource.popConnection(PooledDataSource.java:432)
	at org.apache.ibatis.datasource.pooled.PooledDataSource.getConnection(PooledDataSource.java:89)
	at org.apache.ibatis.transaction.jdbc.JdbcTransaction.openConnection(JdbcTransaction.java:139)
	at org.apache.ibatis.transaction.jdbc.JdbcTransaction.getConnection(JdbcTransaction.java:61)
	at org.apache.ibatis.executor.BaseExecutor.getConnection(BaseExecutor.java:337)
	at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:86)
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:62)
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325)
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109)
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:89)
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147)
	... 36 more
Caused by: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
	at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
	at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1949)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:302)
	at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:296)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1509)
	at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:216)
	at sun.security.ssl.Handshaker.processLoop(Handshaker.java:979)
	at sun.security.ssl.Handshaker.process_record(Handshaker.java:914)
	at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1062)
	at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1375)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1403)
	at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1387)
	at com.mysql.jdbc.ExportControlled.transformSocketToSSLSocket(ExportControlled.java:186)
	... 68 more
Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
	at com.mysql.jdbc.ExportControlled$X509TrustManagerWrapper.checkServerTrusted(ExportControlled.java:302)
	at sun.security.ssl.AbstractTrustManagerWrapper.checkServerTrusted(SSLContextImpl.java:922)
	at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1491)
	... 76 more
Caused by: java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors
	at sun.security.provider.certpath.PKIXCertPathValidator.validate(PKIXCertPathValidator.java:153)
	at sun.security.provider.certpath.PKIXCertPathValidator.engineValidate(PKIXCertPathValidator.java:79)
	at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292)
	at com.mysql.jdbc.ExportControlled$X509TrustManagerWrapper.checkServerTrusted(ExportControlled.java:295)
	... 78 more


Process finished with exit code -1

在这里插入图片描述

最省事的方法是修改数据库连接信息,在链接之后加上“useSSL=false”,直接禁用SSL连接方式。 jdbc.properties文件

在这里插入图片描述

缓存

一级缓存

不需要配置

@Test
public void testfindUserByUId(){
    User user = dao.findUserByUId(3);
    System.out.println(user);

    User user2 = dao.findUserByUId(3);
    System.out.println("第二次查询:"+user2);
}

可以看到 只会查一次

在这里插入图片描述

二级缓存

要配置,在主配置文件里mybatis-config.xml

<settings>
    <!--  开启二级缓存   -->
    <setting name="cacheEnabled" value="true"/>
</settings>
使用注解配置二级缓存

dao

@CacheNamespace(blocking = true)//mybatis基于注解方式实现配置二级缓存
public interface IUserDao {

实现序列化接口

public class User implements Serializable {

测试

@Test
public void testFindUserByUId2(){
    SqlSession  sqlSession1 = sessionFactory.openSession();
    IUserDao IUserDao1= sqlSession1.getMapper(IUserDao.class);

    User user = IUserDao1.findUserByUId(5);
    System.out.println("第一次查询"+user);

    // 查一遍把一级缓存给它关了
    sqlSession1.close();//一级缓存消失

    SqlSession  sqlSession2 = sessionFactory.openSession();
    IUserDao IUserDao2= sqlSession2.getMapper(IUserDao.class);
    User user2 = IUserDao2.findUserByUId(5);
    System.out.println("第二次查询"+user2);
    sqlSession2.close();
    // 再查一遍又把一级缓存给它关了

    /* 我们来看他会不会发起两次请求。
    如果没有发起两次查询,也就意味着二级缓存生效了!!!*/
}

在这里插入图片描述

所以注解的方式比xml的方式方便多了,这两种方式都有人用,我们都应该去掌握。

mybatis plus 简单理解就是比mybatis 要稍微方便一点,所谓的方便就是你学完mybatis 之后再去学mybatis plus你会发现很多东西又被简化掉了。自行感兴趣去了解吧

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/675462.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Park Here:城市停车新神器,让停车不再难

在现代城市的快节奏生活中&#xff0c;停车问题往往成为驾驶者的一大困扰。无论是寻找停车位时的焦虑&#xff0c;还是对停车规则的不了解&#xff0c;都让停车变得不那么简单。然而&#xff0c;随着科技的发展&#xff0c;一款名为“Park Here”的移动应用程序正逐渐改变这一现…

论文精读--Swin Transformer

想让ViT像CNN一样分成几个block&#xff0c;做层级式的特征提取&#xff0c;从而使提取出的特征有多尺度的概念 Abstract This paper presents a new vision Transformer, called Swin Transformer, that capably serves as a general-purpose backbone for computer vision. …

做了几年的广告设计,发现一些东西

我换了多个行业&#xff0c;发现了一些广告设计的一些行业规律&#xff0c;先从面试说起。 他们面试比较倾向是本行业的&#xff0c;找到他们去当前公司来当设计&#xff0c;但是重点&#xff1b;还是不喜欢我这种经常被试用期不合格的情况。 还有甲方公司&#xff0c;经常需要…

【机器学习】【遗传算法】【项目实战】药品分拣的优化策略【附Python源码】

仅供学习、参考使用 一、遗传算法简介 遗传算法&#xff08;Genetic Algorithm, GA&#xff09;是机器学习领域中常见的一类算法&#xff0c;其基本思想可以用下述流程图简要表示&#xff1a; &#xff08;图参考论文&#xff1a;Optimization of Worker Scheduling at Logi…

EMQX Enterprise 5.7 发布:新增会话持久化、消息 Schema 验证、规则引擎调试与追踪功能

EMQX Enterprise 5.7.0 版本现已正式发布&#xff01; 在这个版本中&#xff0c;我们引入了一系列新的功能和改进&#xff0c;包括会话持久化、消息 Schema 验证、规则引擎调试与追踪测试等功能。此外&#xff0c;新版本还进行了多项改进以及 BUG 修复&#xff0c;进一步提升了…

QT 编译Lua 动态库,使用Lua脚本混合编程

一,编译Lua动态库 1,下载lua源码 地址:Lua: downloadhttps://www.lua.org/download.html 2,配置 解压lua源码压缩包,里面有个src文件夹,里面的代码就是lua的源码

TMS320F280049 ECAP模块--capture模式(1)

功能框图 event预分频 如下图所示&#xff0c;可以对输入信号进行预分频。 一次性触发和连续触发 如下图所示&#xff0c;可以进行一次性触发&#xff0c;也可以进行连续触发。 中间计数器的clk是事件1-4&#xff0c;stop是由一次性触发逻辑控制&#xff0c;rst是由ctrfiltre…

【数据结构与算法 经典例题】(C语言)反转链表图文详解

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《数据结构与算法 经典例题》C语言 期待您的关注 ​ 目录 一、问题描述 二、解题思路分析 三、代码实现 一、问题描述 二、解题…

华为机考入门python3--(33)牛客33-整数与IP地址间的转换

分类&#xff1a;进制转换 知识点&#xff1a; 十进制转8位二进制 format(num, 08b) 二进制转十进制 int(binary_str, 2) 列表中元素类型转换 new_list map(int, old_list) 题目来自【牛客】 # 将IP地址转换为十进制形式的整数 def ip_to_int(ip):# map返回的是迭…

SEO之关键词扩展(一)

初创企业搭建网站的朋友看1号文章&#xff1b;想学习云计算&#xff0c;怎么入门看2号文章谢谢支持&#xff1a; 1、我给不会敲代码又想搭建网站的人建议2、新手上云 确定了核心关键词后&#xff0c;接下来就是进行关键词扩展。对一个稍有规模的网站来说&#xff0c;研究几十个…

【计算机毕设】【计算机毕设】基于SpringBoot平台的医疗病历交互系统设计与实现 - 源码免费(私信领取) - 源码免费(私信领取)

免费领取源码 &#xff5c; 项目完整可运行 &#xff5c; v&#xff1a;chengn7890 诚招源码校园代理&#xff01; 1. 研究目的 本项目旨在设计并实现一个基于SpringBoot的医疗病历交互系统&#xff0c;以改善病历管理和医患沟通的效率&#xff0c;提升医疗服务质量。具体目标包…

质数计数问题求解

质数计数问题求解 题目 leetcdoe204 计数质数:https://leetcode.cn/problems/count-primes 给定整数 n ,返回 所有小于非负整数 n 的质数的数量 。 示例1: 输入:n = 10 输出:4 解释:小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 。 示例 2: 输入:n = 0 输出:0 示…

Go 线程同步

一、介绍 通常在 Go 语言中有两种方法可以用来做线程同步 sync.Cond channel channel 的很好理解&#xff0c;当我们从一个 channel 中接收数据的时候&#xff0c;如果里面没有数据&#xff0c;那我们直接就阻塞在那里了。 在 Go 语言中&#xff0c;如果你尝试在已经持有某…

【设计模式】JAVA Design Patterns——Monitor(监视器模式)

&#x1f50d;目的 主要目的是为多个线程或进程提供一种结构化和受控的方式来安全地访问和操作共享资源&#xff0c;例如变量、数据结构或代码的关键部分&#xff0c;而不会导致冲突或竞争条件。 &#x1f50d;解释 通俗描述 监视器模式用于强制对数据进行单线程访问。 一次只允…

基于java的CRM客户关系管理系统(六)

目录 5.3 表现层设计 5.3.1 模型层&#xff08;M&#xff09; 5.3.2 视图层&#xff08;V&#xff09; 5.3.3 控制层&#xff08;C&#xff09; 5.4 系统主要功能模块的实现 5.4.1 登录功能的实现 5.4.2 客户管理的实现 5.5 本章小结 参考文献 前面内容请移步 基于java…

基本元器件 - 电感与磁珠

电感 电感的选型 体积大小电感值所在工作频率开关频率下的电感值为实际需要的电感值线圈的直流阻抗&#xff08;DCR&#xff09;越小越好工作电流应降额至额定饱和电流的 0.7 倍以下&#xff0c;额定 rms 电流&#xff1b;交流阻抗&#xff08;ESR&#xff09;越小越好&#…

10 款在线剽窃检查的 [免费工具]

剽窃或抄袭他人文章而不注明出处&#xff0c;几乎在所有领域都被认为是有害的。然而&#xff0c;学术界最痛恨这种行为。抄袭是对学术诚信的最大威胁。这就是为什么每个教育机构总是希望学生提交无抄袭的作业。 然而&#xff0c;有时学生无意中剽窃了他人的作业&#xff0c;直…

【软件开发】Java学习路线

本路径视频教程均来自尚硅谷B站视频&#xff0c;Java学习课程我已经收藏在一个文件夹下&#xff0c;B站文件夹同时会收藏其他Java视频&#xff0c;感谢关注。指路&#xff1a;https://www.bilibili.com/medialist/detail/ml3113981545 2024Java学习路线&#xff08;快速版&…

命名空间,缺省参数和函数重载

前言&#xff1a;本文章主要介绍一些C中的小语法。 目录 命名空间 namespace的使用 访问全局变量 namespace可以嵌套 不同文件中定义的同名的命名空间可以合并进一个命名空间&#xff0c;并且其中不可以有同名的变量 C中的输入和输出 缺省参数&#xff08;默认参数&#…

超越Devin!姚班带队,他们创大模型编程新世界纪录

超越Devin&#xff01;SWEBench排行榜上迎来了新玩家—— StarShip CodeGen Agent&#xff0c;姚班带队初创公司OpenCSG出品&#xff0c;以23.67%的成绩获得全球第二名的成绩。 同时创造了非GPT-4o基模的最高纪录&#xff08;SOTA&#xff09;。 我们都知道&#xff0c;SWEBe…