欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

mybatis之注解开发

程序员文章站 2022-05-24 20:20:44
...

mybatis注解开发

环境搭建

新建maven工程

先看下完整的测试工程结构
mybatis之注解开发

工程结构说明

  • dao包:和数据库交互的接口(增删改查)
  • entity包:实体定义
  • jdbcConfig.properties:jdbc连接的配置文件
  • SqlMapperConfig.xml:mybatis的配置文件

pom.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>mybatis_annotaion</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 打包方式 -->
   <packaging>jar</packaging>

    <!-- 所有依赖-->
    <dependencies>
        <!-- mybatis依赖 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>

        <!-- mysql依赖 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>

        <!-- 调试工具依赖 -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13</version>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

mybatsi配置

<?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>

    <!-- 引入jdbc配置文件 -->
    <properties resource="com/jdbcConfig.properties"></properties>

    <!-- 环境:配置mybatis的环境 -->
    <environments default="mysql">
        <!-- 环境变量:可以配置多个环境变量,比如使用多数据源时,就需要配置多个环境变量 -->
        <environment id="mysql">
            <!-- 事务管理器 -->
            <transactionManager type="jdbc"></transactionManager>
            <!-- 数据源 -->
            <dataSource type="POOLED">
                <!--
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.1.8:3306/studenms?serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="sa"/>
                -->
                <property name="driver" value="${jdbc.driver}"/>
                <property name="url" value="${jdbc.url}"/>
                <property name="username" value="${jdbc.username}"/>
                <property name="password" value="${jdbc.password}"/>
            </dataSource>
        </environment>
    </environments>

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

这里采用引入jdbc配置文件,也可直接配置,即dataSource节点中注释部分。和dao接口的映射,由于是采用注解开发,因此用package映射。jdbc的配置文件jdbcConfig.properties内如下:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://192.168.1.8:3306/studenms?serverTimezone=UTC
jdbc.username=root
jdbc.password=sa

注意等号后边的字符串不要加双引号,加了双引号之后,在解析配置时候,会将双引号也解析出来,导致无法连接jdbc


查询实现

数据表说明

  • t_user 用户表

mybatis之注解开发

  • t_score 分数表

mybatis之注解开发


实体定义


用户信息实体

package com.entity;

import java.util.List;

public class UserEntity {
    private int id;
    private String user;
    private int role;
    private String name;
    private String email;
    private String pwd;

    public int getId() {
        return id;
    }

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

    public String getUser() {
        return user;
    }

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

    public int getRole() {
        return role;
    }

    public void setRole(int role) {
        this.role = role;
    }

    public String getName() {
        return name;
    }

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

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getPwd() {
        return pwd;
    }

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


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


分数实体

package com.entity;

public class ScoreEntity {
    private int uId;
    private int id;
    private int scores;

    public int getuId() {
        return uId;
    }

    public void setuId(int uId) {
        this.uId = uId;
    }

    public int getId() {
        return id;
    }

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

    public int getScores() {
        return scores;
    }

    public void setScores(int scores) {
        this.scores = scores;
    }

    @Override
    public String toString() {
        return "Score{" +
                "uId=" + uId +
                ", id=" + id +
                ", scores=" + scores +
                '}';
    }
}


dao接口

package com.dao;

import com.entity.UserEntity;
import java.util.List;

public interface IUserDao {

    @Select("select * from t_user")
    List<UserEntity> findAll();

    @Select("select * from t_user where id=#{id}")
    UserEntity findById(Integer id);
}

package com.dao;

import com.entity.ScoreEntity;

import java.util.List;

public interface IScoreDao {

    @Select("select * from t_score")
    List<ScoreEntity> findAll();

    @Select("select * from t_score where id=#{id}")
    ScoreEntity findById();

    @Select("select * from t_score where id=#{id}")
    List<ScoreEntity> findByUserId(Integer userId);
}


测试程序

import com.dao.IScoreDao;
import com.dao.IUserDao;
import com.entity.ScoreEntity;
import com.entity.UserEntity;
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;
import java.util.List;

public class AnnotationTest {
    public static void main(String[] args) throws IOException {
//        读取配置文件
        InputStream stream = Resources.getResourceAsStream("com/SqlMapperConfig.xml");
//        使用SQLSession工厂构建器,创建SQLSession
        SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
        SqlSessionFactory factory = factoryBuilder.build(stream);
//        获取SQLSession对象
        SqlSession session = factory.openSession();
//        获取接口的代理对象(不用实现接口)

        //region 获取用户数据
        IUserDao userDao = session.getMapper(IUserDao.class);
        List<UserEntity> userList = userDao.findAll();
        for (UserEntity userEntity : userList) {
            System.out.println("=====每个用户数据=====");
            System.out.println(userEntity);

        }
        //endregion

        //region 获取分数数据
//        IScoreDao scoreDao = session.getMapper(IScoreDao.class);
//        List<ScoreEntity> scoreList = scoreDao.findByUserId(123);
//        for (ScoreEntity scoreEntity : scoreList) {
//            System.out.println("===每类课程数据====");
//            System.out.println(scoreEntity);
//        }
        //endregion
    }
}

执行获取用户数据代码块结果如下:
mybatis之注解开发

执行获取分数数据代码块结果如下:
mybatis之注解开发

发现一个问题,图中红色部分的字段值要么为0,要么是null,通过上面的数据表可看出,数据库中是有数据的,那为什么没有获取到数据呢?

这是因为mybatis有个要求,实体中定义的字段名称必须和数据表中字段名称保持一致(大小写可忽略),名称一致的字段被读取到了,因此给赋值了,名称不一致的字段没有被读取到,就给了默认值,String类型默认null,Integer类型默认0.

那怎么将自己定义的字段与数据库字段一一对应拿起来,除了名称保持一致,还有什么办法呢?

使用@Results注解,在@select后,加上@Results,先来看一下@Results 和 @Result源码

@Results源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Results {
    String id() default "";

    Result[] value() default {};
}

有id 和 value属性,

id是一个唯一标识的名称

value 它的类型Result[]类型,用于存放映射字段关系

@Result源码

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
@Repeatable(Results.class)
public @interface Result {
    boolean id() default false;

    String column() default "";

    String property() default "";

    Class<?> javaType() default void.class;

    JdbcType jdbcType() default JdbcType.UNDEFINED;

    Class<? extends TypeHandler> typeHandler() default UnknownTypeHandler.class;

    One one() default @One;

    Many many() default @Many;
}

通过查看@Result注解源码发现,它有id,column,property……属性

id表示主键,默认为false;

column表示列,即数据表的列;

property表示属性,即实体中定义的字段;

因此我们就可以用它来进行字段映射

    @Select("select * from t_user")
    @Results(id = "userMap",value = {
            @Result(id = true,column = "id",property = "id"),
            @Result(column = "role",property = "role"),
            @Result(column = "name",property = "name"),
            @Result(column = "email",property = "email"),
            @Result(column = "name",property = "name"),
            @Result(column = "password",property = "pwd"),
    })
    List<UserEntity> findAll();

    @Select("select * from t_user where id=#{id}")
    @ResultMap(value = "userMap")
    UserEntity findById(Integer id);

这里又产生一个问题 @Results注解是写在findAll()方法上,那findById(Integer id)方法怎么办?又要重新写一遍映射?

有@ResultMap以供使用,在@Results中有id属性,它是唯一标识,给它取个名,其它需要用到这个映射的地方直接用id即可,例如:findById(Integer id)方法上的@ResultMap(value = “userMap”)

映射完成后再来执行测试程序,看一下结果:
mybatis之注解开发
mybatis之注解开发

可以看到,数据全部获取成功。

看到这里,又产生一个问题,这一顿操作都是针对单表啊,实际情况肯定最起码都是2个表以上联查,这怎么办?

往下看,使用mybatis进行一对一一对多的联查

多表联合

  • 一对一:一个学科的分数只能是属于一个用户的,分数和用户的关系就是一对一
  • 一对多:一个用户可以有多个科目的分数,用户和分数的关系就是一对多
  • 即时加载:即查询时候一次性将所有数据全部取出,例如
  • 延时加载:需要多少数据就获取多少数据

例如当要查看用户信息,用户又关联的有分数数据,那么就可以先查询用户信息,需要查看分数时,再查相关的分数数据,这就是延时加载的体现,减少不必要的查询消耗,提升效率。如果采用即时加载,查看一个用户信息时候,会把这个用户相关联的分数也会查询出来,假如关联的分数数据有十万、百万级,而又只看了用户信息,没看关联的分数,但是后台却又把这百万级数据给加载出来,这会大大影响体验。

mybatis实现一对一查询

使用@one注解实现一对一,例如图中红色部分
mybatis之注解开发

@one源码如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface One {
    String select() default "";

    FetchType fetchType() default FetchType.DEFAULT;
}

select属性也是注解,它用来查询关联的表,这里可写sql语句,可调用方法,调用方法时,这里填写的一定是方法的全限定路径,由包名、类名、方法名组成。

fetchType这个属性指定了加载方式,即延时加载 和 即时加载

根据分数查询用户,在ScoreEntity中增加UserEntity类型的属性,每类课程数据只对应了一个用户,结果如下
mybatis之注解开发

mybatis实现一对多查询

使用@many注解,如图中红色部分
mybatis之注解开发

@many源码如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({})
public @interface Many {
    String select() default "";

    FetchType fetchType() default FetchType.DEFAULT;
}

源码与@one相同,区别在于sql语句的返回值,因此当返回多条数据时,使用@many

根据用户查询分数,在UserEntity中增加List类型属性,由于用户和分数时一对多关系,查询结果如下:
mybatis之注解开发
可以看到用户123,124都关联了两条分数数据,用户125关联了1条,这就是一对多的体现。

注意事项

mybatis有两种开发方式,除了本文介绍的注解开发之外,另一种是对每个dao接口进行sql的配置,然而这两种方式不能并存,只能选择一种方式进行开发,否则在程序编译期间,会抛出找不到dao接口映射的异常

相关标签: mybatis java