Mybatis学习

Mybatis-2022/09/25


环境:

  • ​ JDK1.8
  • Mysql5.7
  • maven3.6.1
  • IDEA

回顾:

  • JDBC
  • Mysql
  • Java基础
  • Maven
  • Junit

SSM框架:配置文件

最好的方式:看官网文档

1.简介


1.1什么是Mybatis

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a3i15Vzc-1666011193374)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20220925233949003.png)]

  • MyBatis 是一款优秀的持久层框架
  • 它支持自定义 SQL、存储过程以及高级映射
  • MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作
  • MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO(Plain Old Java Objects,普通老式 Java 对象)为数据库中的记录。
  • MyBatis本是apache的一个开源项目iBatis,2010年这个项目由apache software foundation迁移到了[google code](https://baike.baidu.com/item/google code/2346604?fromModule=lemma_inlink),并且改名为MyBatis。
  • 2013年11月迁移到Github。

如何获得mybatis?

  • maven仓库

    
    <dependency>
        <groupId>org.mybatisgroupId>
        <artifactId>mybatisartifactId>
        <version>3.5.2version>
    dependency>
    
  • GitHub:Releases · mybatis/mybatis-3 (github.com)

  • 中文文档:mybatis – MyBatis 3 | 简介

1.2持久化

数据持久化

  • 持久化就是将程序的数据在持久状态和瞬时状态转化的过程
  • 内存:断点即失
  • 数据库(Jdbc),io文件持久化。
  • 生活:冷藏、罐头。

为什么需要持久化?

有一些对象,不能让他丢掉

  • 有一些对象,不能让他丢掉
  • 内存太贵

1.3持久层

Dao层、Service层、Controller层…

  • 完成持久化工作的代码块
  • 层界限十分明显

1.4为什么需要Mybatis

  • 帮助程序员将数据存入到数据库中

  • 方便

  • 传统的JDBC代码太复杂。简化。框架。自动化。

  • 不用Mybatis也可以。更容易上手。技术没有高低之分

  • 优点:

    • 简单易学
    • 灵活
    • sql和代码的分离,提高了可维护性。
    • 提供映射标签,支持对象与数据库的ORM字段关系映射。
    • 提供对象关系映射标签,支持对象关系组建维护。
    • 提供xml标签,支持编写动态sql。

    最重要的一点:使用的人多!

2.第一个Mybatis程序


思路:搭建环境–>导入Mybatis–>编写代码–>测试

2.1搭建环境

create database mytabis;

use mytabis;

create table user(
    id int not null primary key ,
    name varchar(30) default null,
    pwd varchar(30) default null
)engine =INNODB default charset =utf8;

insert into user(id, name, pwd) VALUES (1,'西游记','吴承恩'),(2,'水浒传','施耐庵'),(3,'三国演义','罗贯中');

新建项目

  1. 新建一个普通的maven项目
  2. 删除src目录
  3. 导入maven依赖

    <dependencies>
        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>5.1.47version>
        dependency>
        
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.2version>
        dependency>
        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.12version>
        dependency>
    dependencies>

2.2创建一个模块

  • 编写mybatis的核心配置文件

DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "https://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.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            dataSource>
        environment>
    environments>
configuration>
  • 编写mybatis的工具类
package com.kuang.utils;


import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.IOException;
import java.io.InputStream;

//sqlSessionFactory -->sqlSession
public class MybatisUtils {

    private static SqlSessionFactory sqlSessionFactory;

    static {
        try {
            //使用Mybatis第一步获取sqlSessionFactory对象
            String resource = "mybatis-config-xml";
            InputStream inputStream = Resources.getResourceAsStream(resource);
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //既然有了 SqlSessionFactory,顾名思义,我们可以从中获得 SqlSession 的实例。
    // SqlSession 提供了在数据库执行 SQL 命令所需的所有方法。你可以通过 SqlSession 实例来直接执行已映射的 SQL 语句。
    public static SqlSession getSqlSession(){
        return sqlSessionFactory.openSession();
    }
}

关于Java中static的使用有以下四种情况:

**1、静态成员变量
** 被static修饰的成员变量,叫静态成员变量或类变量;没有被static修饰的变量,叫实例变量。

两者的区别是:
静态成员变量在内存中只有一分拷贝(节省内存),JVM只为静态成员变量分配一次内存,在加载类的过程中完成静态成员变量的内存分配,可用类名直接访问(方便),当然也可以通过对象实例来访问(但是这是不推荐的)。 所以当静态成员变量内存分配好了后,所有的实例对象共同维护静态成员变量(类变量),任何一个对象对实例变量的修改都会影响到其他对象实例对该变量的访问。
对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活)。
**2、静态成员方法
** 静态方法可以直接通过类名调用,任何的实例也都可以调用,因此静态方法中不能用this和super关键字,不能直接访问所属类的实例变量和实例方法(就是不带static的成员变量和成员成员方法),只能访问所属类的静态成员变量和静态成员方法。因为实例成员与特定的对象关联!这个需要去理解,想明白其中的道理,不是记忆!!!
因为static方法独立于任何实例,因此static方法必须被实现,而不能是抽象的abstract。
3、静态代码块
static代码块也叫静态代码块,是在类中独立于类成员的static语句块,可以有多个,位置可以随便放,它不在任何的方法体内,JVM加载类时会执行这些静态的代码块,如果static代码块有多个,JVM将按照它们在类中出现的先后顺序依次执行它们,每个代码块只会被执行一次。

静态代码块在类加载时仅仅执行一次,而代码块在类加载时不执行,而是在每次对象创建时都会执行,并且先于构造函数执行。

4、静态嵌套类

为了生成对立于外部类对象的嵌套类对象,就需要将嵌套类生命为static。

实例代码:

public class Test {
	// 嵌套类
	public class InnerClass {

	}

	// 静态嵌套类
	public static class StaticInnerClass {
		public StaticInnerClass() {
			System.out.println("--静态嵌套类构造器执行。");
		}
	}

	// 静态成员变量
	public static String param = "--静态成员变量值。";
	// 静态代码块
	static {
		System.out.println("--静态代码块执行。");
	}
	// 代码块
	{
		System.out.println("--代码块执行。");
	}

	// 静态成员方法
	public static void StaticMethod() {
		System.out.println("--静态成员方法执行。");
	}

	// 构造器?
	private Test() {
		System.out.println("--构造器执行。");
	}

	// Main
	public static void main(String[] args) {
		Test app1 = new Test();
		Test app2 = new Test();
		System.out.println("------------两个对象生成完成。----------------");
		// 使用类名调用静态成员方法
		Test.StaticMethod();
		// 使用实例对象调用静态成员方法
		app1.StaticMethod();
		// 使用类名调用静态成员变量
		System.out.println(Test.param);
		// 使用实例对象调用静态成员变量
		System.out.println(app1.param);
		// 所有对象共同维护静态成员变量
		System.out.println(app2.param);
		Test.StaticInnerClass sobj = new Test.StaticInnerClass();
	}
}
运行结果:
--静态代码块执行。
--代码块执行。
--构造器执行。
--代码块执行。
--构造器执行。
------------两个对象生成完成。----------------
--静态成员方法执行。
--静态成员方法执行。
--静态成员变量值。
--静态成员变量值。
--静态成员变量值。
--静态嵌套类构造器执行。

2.3编写代码

  • 实体类
package com.kuang.pojo;
//实体类
public class User {
    private int id;
    private String name;
    private String pwd;

    public User() {
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}

  • Dao接口
public interface UserDao {
    List<User> getUserList();
}
  • 接口实现类由原来的UserDaolmpl转变为一个Mapper配置文件

DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "https://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.kuang.dao.UserDao">

    
    <select id="getUserList" resultType="com.kaung.pojo.User">
        select * from mybatis,user
    select>

mapper>

2.4测试

  • junit测试
package com.kuang.dao;

import com.kuang.pojo.User;
import com.kuang.utils.MybatisUtils;
import org.apache.ibatis.session.SqlSession;
import org.junit.Test;

import java.util.List;

public class UserDaoTest {
    @Test
    public void test(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        //方式一:getMapper
        UserDao userDao = sqlSession.getMapper(UserDao.class);
        List<User> userList = userDao.getUserList();

        for (User user : userList) {
            System.out.println(user);
        }
        //关闭SqlSession
        sqlSession.close();
    }
}

可能会遇到的问题:

  1. 配置文件没有注册
  2. 绑定接口错误
  3. 方法名不对
  4. 返回类型不对
  5. Maven导出资源问题

3.CRUD


1.namespace中的包名要和Dao/mapper接口的包名一致

2.select

选择、查询语句:

  • ​ id:就是对应的namespace中的方法名;
  • resultType:Sql语句执行的返回值
  • parameterType:参数类型
查询全部用户
List<User> getUserList();
<select id="getUserList" resultType="com.kuang.pojo.User">
    select * from mytabis.user;
select>
    @Test
    public void test(){
        //第一步:获得SqlSession对象
        SqlSession sqlSession = MybatisUtils.getSqlSession();
        try {

            //方式一:getMapper
            UserMapper userDao = sqlSession.getMapper(UserMapper.class);
            List<User> userList = userDao.getUserList();

            //方式二
//        List userList = sqlSession.selectList("com.kuang.dao.getUserList");

            for (User user : userList) {
                System.out.println(user);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭SqlSession
            sqlSession.close();
        }

    }
根据ID查询用户
1.编写接口
User getUserById(int id);
2.编写对应的mapper中的sql语句
<select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
    select * from mytabis.user where id = #{id};
select>
3.测试
@Test
public void getUserById(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    User user = mapper.getUserById(1);
    System.out.println(user);
    sqlSession.close();
}

3.insert

1.编写接口
int addUser(User user);
2.编写对应的mapper中的语句
<insert id="addUser" parameterType="com.kuang.pojo.User">
    insert into mytabis.user (id,name,pwd) values(#{id},#{name},#{pwd});
insert>
3.测试
//增删改需要提交事务
@Test
public void addUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int res = mapper.addUser(new User(4, "红楼梦", "曹雪芹"));
    if (res > 0) {
        System.out.println("插入成功");
    }
    //提交事务
    sqlSession.commit();
    sqlSession.close();
}

4.update

修改用户

1.编写接口
int updateUser(User user);
2.编写对应的的mapper语句
<update id="updateUser" parameterType="com.kuang.pojo.User">
    update mytabis.user set name=#{name},pwd=#{pwd} where id = #{id};
update>
3.测试
@Test
public void updateUser(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int res = mapper.updateUser(new User(2, "老人与海", "海明威"));
    if (res > 0) {
        System.out.println("修改成功");
    }
    sqlSession.commit();
    sqlSession.close();
}

5.delete

删除用户

1.编写接口
int deleteUser(int id);
2.编写对应的mapper语句
<delete id="deleteUser" parameterType="int">
    delete from mytabis.user where id = #{id};
delete>
3.测试
@Test
public void deleteUser() {
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    int res = mapper.deleteUser(1);
    if (res > 0) {
        System.out.println("删除成功");
    }
    sqlSession.commit();
    sqlSession.close();
}

注意点:

  • ​ 增删改需要提交事务

6.分析错误

  • ​ 标签不要匹配错
  • resource绑定mapper,需要使用路径
  • NullPointerException,没有注册到资源
  • 输出的xml文件中存在中文乱码问题
  • maven资源没有导出问题

7.万能Map

假设,我们的实体类,或者数据库中的表,字段或者参数过多,我们应当考虑Map

//万能的Map
int addUser2(Map<String, Object> map);
<insert id="addUser" parameterType="map">
    insert into mytabis.user (id,pwd) values (#{userid},#{password});
insert>
@Test
public void addUser2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("userid", 5);
    map.put("password", "海底两万里");
    mapper.addUser2(map);
    sqlSession.commit();
    sqlSession.close();
}
User getUserById2(Map<String, Object> map);
<select id="getUserById2" parameterType="map" resultType="com.kuang.pojo.User">
    select * from mytabis.user where id = #{helloid} and name = #{name};
select>
@Test
public void getUserById2(){
    SqlSession sqlSession = MybatisUtils.getSqlSession();
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    Map<String, Object> map = new HashMap<String, Object>();
    map.put("helloid",1);
    mapper.getUserById2(map);
    sqlSession.close();
}

Map传递参数,直接在sql中传递参数即可!【parameterType=“map”】

对象传递参数,直接在sql中取对象的属性即可!【parameterType=“Object”】

只有一个基本类型参数的情况下,可以直接在sql中取到!

多个参数用Map,或者注解!

8.思考题

模糊查询怎么写?

1. Java代码之下的时候,传递通配符%%
List<User> userList = mapper.getUserLike("%红%");

​ 2. 在sql拼接中使用通配符

select * from mytabis.user where name like "%"{value}"%";

4.配置解析


1.核心配置文件

  • mybatis-config.xml
  • Mybatis的配置文件包含了会深深影响Mybatis行为的设置和属性信息
configuration(配置)
properties(属性)
settings(设置)
typeAliases(类型别名)
typeHandlers(类型处理器)
objectFactory(对象工厂)
plugins(插件)
environments(环境配置)
environment(环境变量)
transactionManager(事务管理器)
dataSource(数据源)
databaseIdProvider(数据库厂商标识)
mappers(映射器)

2.环境配置(environments)

Mybatis可以适应多种环境

不过要记住:尽管可以配置多个环境,但每个 SqlSessionFactory 实例只能选择一种环境。

学会使用配置多套运行环境

Mybatis默认的事务管理器就是JDBC,连接池:POOLED

3.属性(properties)

我们可以通过properties属性来实现引用配置文件

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

编写一个配置文件

db.properties

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

在xml,所有的标签都可以规定其顺序

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MJQE8GQr-1666011193375)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221006191843591.png)]

在核心配置中映入

<properties resource="db.properties">
    <property name="username" value="root"/>
    <property name="pwd" value="123456"/>
properties>
  • 可以直接引用外部文件
  • 可以在其中增加一些属性配置
  • 如果两个文件有同一个字段,优先使用外部配置文件

4.类型别名(typeAliases)

  • 类型别名是为java类型设置一个短的名字
  • 存在的意义仅在于用来减少类完全限定名的冗余
<typeAliases>
    <typeAlias type="com.kuang.pojo.User" alias="User"/>
typeAliases>

也可以指定一个包名,Mybatis会在包名下面搜索需要的Java Bean,比如:

<typeAliases>
    <package name="com.kuang.pojo"/>
typeAliases>

在实体类比较少的时候,使用第一种方式

如果实体类十分多,建议使用第二种

第一种可以DIY别名,第二种则不行,如果非要改,需要在实体上增加注解

这样的话就得把xml文件里的完全限定名都改过来,不然会报错

@Alias("user") public class User {

5.设置

这是 MyBatis 中极为重要的调整设置,它们会改变 MyBatis 的运行时行为。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RNEDR34n-1666011193376)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221006200853249.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WG1yTfTs-1666011193376)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221006200917731.png)]

6.其他配置

  • typeHandlers(类型处理器)
  • objectFactory(对象工厂)
  • plugins(插件)
    • mybatis-generator-core
    • mybatis-plus
    • 通用mapper

7.映射器(mappers)

MapperRegistry:注册绑定我们的Mapper文件;

方式一:【推荐使用】


<mappers>
	<mapper resource="com/kuang/dao/UserMapper.xml"/>
mappers>

方式二:使用class文件绑定注册

<mappers>
    <mapper class="com.kuang.dao.UserMapper"/>
mappers>

注意点:

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

方式三:使用扫描包进行注入

<mappers>
    <package name="com.kuang.dao"/>
mappers>

8.生命周期和作用域

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MzeJAxDV-1666011193377)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221006233239614.png)]

生命周期和作用域是至关重要的,因为错误的使用会导致非常严重的并发问题。

SqlSessionFactoryBuilder:

  • 一旦创建了 SqlSessionFactory,就不再需要它了。
  • 局部变量

SqlSessionFactory:

  • 说白了就是可以想象为:数据库连接池
  • SqlSessionFactory一旦被创建就应该在应用的运行期间一直存在,没有任何理由丢弃它或重新创建另一个实例。
  • 因此 SqlSessionFactory 的最佳作用域是应用作用域。
  • 最简单的就是使用单例模式或者静态单例模式

SqlSession

  • 连接到连接池的请求!
  • 关闭
  • SqlSession 的实例不是线程安全的,因此是不能被共享的,所以它的最佳的作用域是请求或方法作用域。
  • 用完之后需要赶紧关闭,否则资源被占用
  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ihL161SN-1666011193377)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221006234723571.png)]

这里面得每一个Mapper,就代表一个具体的业务

5.解决属性名和字段名不一致得问题


1.问题

数据库中得字段

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CNRh9uUJ-1666011193377)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221006235013522.png)]

新建一个项目,拷贝之前的,测试实体类字段不一致得情况

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RzqQY80s-1666011193378)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221008195319608.png)]

测试出现问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-H3eKSjDq-1666011193378)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221008195401631.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b6xryuoo-1666011193378)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221008195607937.png)]

解决方案:

  • 起别名
    <select id="getUserById" parameterType="int" resultType="com.kuang.pojo.User">
        select id,name,pwd as password from mytabis.user where id = #{id};
    select>

2.resultMap

结果集映射


    <resultMap id="UserMap" type="User">
        
        <result column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="pwd" property="password"/>
    resultMap>
    <select id="getUserById" resultMap="UserMap">
        select id,name,pwd from mytabis.user where id = #{id};
    select>
  • resultMap 元素是 MyBatis 中最重要最强大的元素。
  • ResultMap 的设计思想是,对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了。
  • ResultMap 的优秀之处——你完全可以不用显式地配置它们。
  • 如果这个世界总是这么简单就好了。

6.日志


6.1日志工厂

如果一个数据库操作,出现了异常,我们需要排错。日志就是最好的助手!

曾经:sout、debug

现在:日志工厂!

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZyOMiZRo-1666011193378)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221008203050761.png)]

  • SLF4J
  • LOG4J【掌握】
  • LOG4J2
  • JDK_LOGGING
  • COMMONS_LOGGING
  • STDOUT_LOGGING【掌握】
  • NO_LOGGING

在Mybatis中具体使用哪一个日志实现,在设置中设定

STDOUT_LOGGING标准日志输出

在mybatis核心配置文件中,配置我们的日志

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-57grjSxB-1666011193379)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221008234815054.png)]

6.2Log4j

什么是log4j:

  • Log4j是Apache的一个开源项目,通过使用Log4j,我们可以控制日志信息输送的目的地是控制台、文件、GUI组件
  • 我们也可以控制每一条日志的输出格式
  • 通过定义每一条日志信息的级别,我们能够更加细致地控制日志的生成过程
  • 可以通过一个配置文件来灵活地进行配置,而不需要修改应用的代码
  1. 先导入log4j的包
<dependency>
    <groupId>log4jgroupId>
    <artifactId>log4jartifactId>
    <version>1.2.17version>
dependency>
  1. log4j.properties
#将等级为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/xu.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
  1. 配置log4j为日志的实现
<settings>
    <setting name="logImpl" value="LOG4J"/>
settings>

4.log4j的使用,直接测试运行刚才的查询

"C:\Program Files\Java\jdk1.8.0_333\bin\java.exe" -ea -Didea.test.cyclic.buffer.size=1048576 "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\lib\idea_rt.jar=62169:C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\lib\idea_rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\plugins\junit\lib\junit5-rt.jar;C:\Program Files\JetBrains\IntelliJ IDEA 2022.2\plugins\junit\lib\junit-rt.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_333\jre\lib\rt.jar;C:\Users\22343\Desktop\EndWeb\Mybatis-Study\mybatis-03\target\test-classes;C:\Users\22343\Desktop\EndWeb\Mybatis-Study\mybatis-03\target\classes;D:\repository\log4j\log4j\1.2.17\log4j-1.2.17.jar;D:\repository\mysql\mysql-connector-java\8.0.30\mysql-connector-java-8.0.30.jar;D:\repository\com\google\protobuf\protobuf-java\3.19.4\protobuf-java-3.19.4.jar;D:\repository\org\mybatis\mybatis\3.5.11\mybatis-3.5.11.jar;D:\repository\junit\junit\4.13.2\junit-4.13.2.jar;D:\repository\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar" com.intellij.rt.junit.JUnitStarter -ideVersion5 -junit4 dao.UserDaoTest,getUserById
[org.apache.ibatis.logging.LogFactory]-Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
[org.apache.ibatis.logging.LogFactory]-Logging initialized using 'class org.apache.ibatis.logging.log4j.Log4jImpl' adapter.
[org.apache.ibatis.io.VFS]-Class not found: org.jboss.vfs.VFS
[org.apache.ibatis.io.JBoss6VFS]-JBoss 6 VFS API is not available in this environment.
[org.apache.ibatis.io.VFS]-Class not found: org.jboss.vfs.VirtualFile
[org.apache.ibatis.io.VFS]-VFS implementation org.apache.ibatis.io.JBoss6VFS is not valid in this environment.
[org.apache.ibatis.io.VFS]-Using VFS adapter org.apache.ibatis.io.DefaultVFS
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/pojo
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/pojo
[org.apache.ibatis.io.DefaultVFS]-Reader entry: User.class
[org.apache.ibatis.io.DefaultVFS]-Listing file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/pojo
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/pojo/User.class
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/pojo/User.class
[org.apache.ibatis.io.DefaultVFS]-Reader entry: ����   4 =
[org.apache.ibatis.io.ResolverUtil]-Checking to see if class com.kuang.pojo.User matches criteria [is assignable to Object]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.datasource.pooled.PooledDataSource]-PooledDataSource forcefully closed/removed all connections.
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao
[org.apache.ibatis.io.DefaultVFS]-Reader entry: UserMapper.class
[org.apache.ibatis.io.DefaultVFS]-Reader entry: UserMapper.xml
[org.apache.ibatis.io.DefaultVFS]-Listing file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao/UserMapper.class
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao/UserMapper.class
[org.apache.ibatis.io.DefaultVFS]-Reader entry: ����   4  	 
[org.apache.ibatis.io.DefaultVFS]-Find JAR URL: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao/UserMapper.xml
[org.apache.ibatis.io.DefaultVFS]-Not a JAR: file:/C:/Users/22343/Desktop/EndWeb/Mybatis-Study/mybatis-03/target/classes/com/kuang/dao/UserMapper.xml
[org.apache.ibatis.io.DefaultVFS]-Reader entry: 
[org.apache.ibatis.io.ResolverUtil]-Checking to see if class com.kuang.dao.UserMapper matches criteria [is assignable to Object]
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Opening JDBC Connection
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Created connection 1064265473.
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Setting autocommit to false on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3f6f6701]
[com.kuang.dao.UserMapper.getUserById]-==>  Preparing: select id,name,pwd from mytabis.user where id = ?;
[com.kuang.dao.UserMapper.getUserById]-==> Parameters: 2(Integer)
[com.kuang.dao.UserMapper.getUserById]-<==      Total: 1
User{id=2, name='老人与海', password='海明威'}
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Resetting autocommit to true on JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3f6f6701]
[org.apache.ibatis.transaction.jdbc.JdbcTransaction]-Closing JDBC Connection [com.mysql.cj.jdbc.ConnectionImpl@3f6f6701]
[org.apache.ibatis.datasource.pooled.PooledDataSource]-Returned connection 1064265473 to pool.

进程已结束,退出代码0

简单使用

  1. 在要使用Log4j的类中,导入包import org.apache.log4j.Logger;
  2. 日志对象,参数为当前类的class
static Logger logger= Logger.getLogger(UserDaoTest .class);
  1. 日志级别
logger.info("info:进入了testLog4j");
logger.debug("debug:进入了testLog4j");
logger.error("error:进入了testLog4j");

7.分页


思考:为什么要分页?

  • 减少数据的处理量

使用limit分页

select * from mytabis.user limit startIndex,pageSize;

使用Mybatis实现分页,核心SQL

  1. 接口

    List<User> getUserByLimit(Map<String, Integer> map);
    
  2. Mapper.xml

    <select id="getUserByLimit" parameterType="map" resultMap="UserMap">
        select * from mytabis.user limit #{startIndex},#{pageSize};
    select>
    
  3. 测试

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

8.使用注解开发

8.1面向接口编程

面向接口编程的根本原因:解耦,可拓展,提高复用,分层开发中、上层不用管具体的实现,大家都遵守共同的标准,使得开发变得容易,规范性好

8.2使用注解开发

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yLmaPVYk-1666011193379)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221010225948263.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-raKSsk9p-1666011193379)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221010230006336.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2KF18KLI-1666011193380)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221010230018856.png)]

8.3CRUD

我们可以在工具类创建的时候实现自动提交事务!

public static SqlSession getSqlSession(){
    return sqlSessionFactory.openSession(true);
}

编写接口,增加注解

@Select("select * from mytabis.user")
List<User> getUsers();

//方法存在多个参数,所有的参数前面必须加上@Param("id")注解
@Select("select * from mytabis.user where id =#{id}")
User getUserBuID(@Param("id") int id);

@Insert("insert into mytabis.user (id,name,pwd) values (#{id},#{name},#{password})")
int addUser(User user);

@Update("update mytabis.user set name=#{name},pwd=#{password} where id=#{id}")
int updateUser(User user);

@Delete("delete from mytabis.user where id = #{id}")
int deleteUser(@Param("id") int id);

测试类

【注意:我们必须要将接口注册绑定到我们的核心配置文件中】

关于@Param()注解

  • 基本类型的参数或者String类型,需要加上
  • 引用类型不需要加
  • 如果只有一个基本类型的话,可以忽略,但是建议大家都加上
  • 我们在SQL中引用的就是我们这里的@Param()中设定的属性名

#{} 与 ${}的区别

9.Lombok


  • Java libary
  • plugs
  • build tools
  • with one annotation your class

使用步骤:

  1. 在IDEA中安装Lombok插件

  2. 在项目中导入lombok的jar包

    <dependency>
        <groupId>org.projectlombokgroupId>
        <artifactId>lombokartifactId>
        <version>1.18.24version>
    dependency>
    
  3. 在实体类上加注解即可

    package com.kuang.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    //实体类
    //@Alias("user")
    public class User {
        private int id;
        private String name;
        private String password;
    
    }
    
@Getter and @Setter
@FieldNameConstants
@ToString
@EqualsAndHashCode
@AllArgsConstructor, @RequiredArgsConstructor and @NoArgsConstructor
@Log, @Log4j, @Log4j2, @Slf4j, @XSlf4j, @CommonsLog, @JBossLog, @Flogger, @CustomLog
@Data
@Builder
@SuperBuilder
@Singular
@Delegate
@Value
@Accessors
@Wither
@With
@SneakyThrows
@StandardException
@val
@var
experimental @var
@UtilityClass

@Data:无参构造,get、set、tostring、hashcode、equals

说明:

@Data:无参构造,get、set、tostring、hashcode、equals
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode

10.多对一处理


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KrykucGv-1666011193380)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221011225359600.png)]

  • 多个学生,对应一个老师

  • 对于学生这边而言,关联…多个学生关联一个老师【多对一】

  • 对于老师而言,集合,一个老师有很多学生【一对多】

  • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-mais3sRj-1666011193380)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221011232032997.png)]

  • use mytabis;
    
    create table teacher(
        id int 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 not null,
        name varchar(30) default null,
        tid int default null,
        key fktid (tid),
        primary key (id),
        constraint fktid foreign key (tid) references teacher (id)
    ) engine = INNODB
      charset = utf8;
    
    show create table student;
    
    INSERT INTO mytabis.student (id, name, tid) VALUES (1, '小红', 1);
    INSERT INTO mytabis.student (id, name, tid) VALUES (2, '小明', 1);
    INSERT INTO mytabis.student (id, name, tid) VALUES (3, '小张', 1);
    INSERT INTO mytabis.student (id, name, tid) VALUES (4, '小李', 1);
    INSERT INTO mytabis.student (id, name, tid) VALUES (5, '小王', 1);
    
    

测试环境搭建

  1. 导入lombok
  2. 新建实体类Teacher,Student
  3. 建立Mapper接口
  4. 建立Mapper.xml接口
  5. 在核心配置文件中绑定注册我们的Mapper接口或者文件【方式很多,随心选】
  6. 测试查询是否能够成功

按照查询嵌套处理

<select id="getStudent" resultMap="StudentTeacher">
    select * from student;
select>
<resultMap id="StudentTeacher" type="Student">
    <result property="id" column="id"/>
    <result property="name" column="name"/>
    
    <association property="teacher" column="tid" javaType="Teacher" select="getTeacher"/>
resultMap>
<select id="getTeacher" resultType="Teacher">
    select * from mytabis.teacher where id=#{id};
select>

按照结果嵌套处理

<select id="getStudent2" resultMap="StudentTeacher2">
    select s.id sid,t.name tname,s.name sname from mytabis.student s ,teacher t where s.tid = t.id;
select>
<resultMap id="StudentTeacher2" type="Student">
    <result property="id" column="sid"/>
    <result property="name" column="name"/>
    <association property="teacher" javaType="Teacher">
        <result property="name" column="tname"/>
    association>
resultMap>

回顾Mysql多对一查询方式:

  • 子查询
  • 联表查询

11.一对多


比如:一个老师拥有多个学生!

对于老师而言,就是一对多的关系!

1. 环境搭建,和刚才一样

实体类

package com.kuang.pojo;

import lombok.Data;

@Data
public class Student {
    private int id;
    private String name;

    private int tid;
}
package com.kuang.pojo;

import lombok.Data;

import java.util.List;

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

}

小结

  1. 关联-association【多对一】
  2. 集合-collection 【一对多】
  3. javaType & ofType
    1. javaType用来指定实体类中属性的类型
    2. ofType用来指定映射到List或者集合中的pojo类型,泛型中的约束类型

注意点:

  • 保证SQL的可读性,尽量保证通俗易懂
  • 注意一对多和多对一中,属性名和字段的问题
  • 如果问题不好排查错误,可以使用日志,建议使用Log4j

面试高频

  • MySql引擎
  • InnoDB底层原理
  • 索引
  • 索引优化

12.动态SQL


什么是动态SQL:动态SQL就是根据不同的条件生成不同的SQL语句

在 MyBatis 之前的版本中,需要花时间了解大量的元素。借助功能强大的基于 OGNL 的表达式,MyBatis 3 替换了之前的大部分元素,大大精简了元素种类,现在要学习的元素种类比原来的一半还要少。

  • if
  • choose (when, otherwise)
  • trim (where, set)
  • foreach

搭建环境

CREATE TABLE `blog`(
`id` VARCHAR(50) NOT NULL COMMENT '博客id',
`title` VARCHAR(100) NOT NULL COMMENT '博客标题',
`author` VARCHAR(30) NOT NULL COMMENT '博客作者',
`create_time` DATETIME NOT NULL COMMENT '创建时间',
`views` INT(30) NOT NULL COMMENT '浏览量'
)ENGINE=INNODB DEFAULT CHARSET=utf8;

创建一个基础工程

  1. 导包

  2. 编写配置文件

  3. 编写实体类

    package com.kuang.pojo;
    
    import lombok.Data;
    
    import java.util.Date;
    @Data
    public class Blog {
        private int id;
        private String title;
        private String author;
        private Date creatTime;
        private int views;
    }
    
  4. 编写实体类对应的Mapper接口和Mapper.xml

IF

<select id="queryBlogIF" parameterType="map" resultType="blog">
    select * from mytabis.blog where 1=1
    <if test="title!=null">
        and title = #{title}
if>
    <if test="author!=null">
        and author = #{author}
if>
    select>

choose(when,otherwise)

<select id="queryBlogChoose" parameterType="map" resultType="blog">
    select * from mytabis.blog
    <where>
        <choose>
            <when test="title!=null">
                title=#{title}
            when>
            <when test="author!=author">
                and author=#{author}
            when>
            <otherwise>
                views=#{views}
            otherwise>
        choose>
    where>
select>

trim(where,set)

<where>
    <if test="title!=null">
        and title = #{title}
    if>
    <if test="author!=null">
        and author = #{author}
    if>
where>
<update id="updateBlog" parameterType="map">
    update mytabis.blog
    <set>
        <if test="title!=null">
            title=#{title},
        if>
        <if test="author!=null">
            author=#{author},
        if>
    set>
    where id=#{id};
update>

所谓的动态SQL,本质还是SQL语句,只是我们可以在SQL层面,去执行一个逻辑代码

SQL片段

有的时候,我们可能会将一些功能的部分抽取出来,方便复用

  1. 使用SQL标签抽取公共部分

    <sql id="if-title-author">
        <if test="title!=null">
            title=#{title},
        if>
        <if test="author!=null">
            author=#{author},
        if>
    sql>
    
    1. 在需要使用的地方使用include标签引用即可
<include refid="if-title-author">include>

注意事项:

  • 最好基于单表来定义SQL片段

Foreach

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u72P2Ldf-1666011193381)(C:\Users\22343\AppData\Roaming\Typora\typora-user-images\image-20221016085010919.png)]

select * from mytabis.user where 1=1 and
	<foreach item="id" collection="ids"
             open="(" separator="or" close=")">
        #{id}
	foreach>
(id=1 or id=2 or id=3)

动态SQL就是在拼接SQL语句,我们只要保证SQL的正确性,按照SQL的格式,去排列组合就可以了

建议:

  • 现在Mysql中写出完整的SQL,再对应的去修改成为我们的动态SQL实现通用即可

13.缓存


13.1简介

查询:连接数据库,耗资源

一次查询的结果,给他暂存在一个可以直接收到的地方–>内存:缓存

我们再次查询相同数据的时候,直接走缓存,就不用走数据库啦

  1. 什么是缓存[Cache]?
    • 存在内存中的临时数据

你可能感兴趣的:(笔记,mybatis,学习,java)