mybatis之注解开发

文章目录

  • mybatis注解开发
    • 环境搭建
        • 新建maven工程
        • 工程结构说明
        • pom.xml配置
        • mybatsi配置
    • 查询实现
        • 数据表说明
        • 实体定义
        • dao接口
        • 测试程序
    • 多表联合
        • mybatis实现一对一查询
        • mybatis实现一对多查询
    • 注意事项

mybatis注解开发

环境搭建

新建maven工程

先看下完整的测试工程结构
mybatis之注解开发_第1张图片

工程结构说明

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

pom.xml配置


<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.0modelVersion>

    <groupId>org.examplegroupId>
    <artifactId>mybatis_annotaionartifactId>
    <version>1.0-SNAPSHOTversion>

    
   <packaging>jarpackaging>

    
    <dependencies>
        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.5.4version>
        dependency>

        
        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <version>8.0.16version>
        dependency>

        
        <dependency>
            <groupId>junitgroupId>
            <artifactId>junitartifactId>
            <version>4.13version>
            <scope>testscope>
        dependency>

    dependencies>

project>

mybatsi配置




<configuration>

    
    <properties resource="com/jdbcConfig.properties">properties>

    
    <environments default="mysql">
        
        <environment id="mysql">
            
            <transactionManager type="jdbc">transactionManager>
            
            <dataSource type="POOLED">
                
                <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之注解开发_第2张图片

  • t_score 分数表

mybatis之注解开发_第3张图片


实体定义


用户信息实体

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 scoreList = scoreDao.findByUserId(123);
//        for (ScoreEntity scoreEntity : scoreList) {
//            System.out.println("===每类课程数据====");
//            System.out.println(scoreEntity);
//        }
        //endregion
    }
}

执行获取用户数据代码块结果如下:
mybatis之注解开发_第4张图片

执行获取分数数据代码块结果如下:
mybatis之注解开发_第5张图片

发现一个问题,图中红色部分的字段值要么为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之注解开发_第6张图片
mybatis之注解开发_第7张图片

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

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

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

多表联合

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

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

mybatis实现一对一查询

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

@one源码如下:

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

    FetchType fetchType() default FetchType.DEFAULT;
}

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

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

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

mybatis实现一对多查询

使用@many注解,如图中红色部分
mybatis之注解开发_第9张图片

@many源码如下:

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

    FetchType fetchType() default FetchType.DEFAULT;
}

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

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

注意事项

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

你可能感兴趣的:(mybatis)