Mybatis工具类和关联操作

MyBatis工具类和关联操作

MyBatis工具类

由于我们基础的Mybatis在操作数据库时,虽然不需要写Dao接口的实体类,但是仍然需要重复的操作:通过Mybatis来加载配置文件.构建SqlSession的工厂来创建SqlSession的对象.在通过SqlSession的对象来获取实体类的对象,甚至是对事务的提交,这些操作都是重复的,因此我们设计一个工具类,对Mybatis的操作进行一个封装,将必须要做的事情,将其封装到静态代码块,在类加载时进行执行,将可能会执行的操作封装为一个静态方法,在使用时进行调用就可以了.简化我们的操作,去掉了很多冗余的代码

下面给出MyBatis工具类的详细代码:

package per.util;


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;



/**
 * @author 雷雨
 * @date 2020/6/16 15:06
 *
 * mybatis工具类
 *      1.加载配置
 *      2.创建SqlSession工厂
 *      3.创建Session
 *      4.事务的管理
 *      5.Mapper获取
 */
public class MybatisUtil {
    //创建线程工厂
    private static SqlSessionFactory sqlSessionFactory;
    //创建ThreadLocal绑定当前线程中的SqlSession
    private static final ThreadLocal<SqlSession> t1=new ThreadLocal<SqlSession>();
    static{//配置加载信息,构建session工厂
        try {
            //1.加载配置文件
            InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
            sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    public  static  SqlSession openSession(){
        //注意这里的SqlSession和我们普通的jdbc操作中的Connection对象很相似,是线程唯一,全局不唯一的
        //因此我们需要先看看在当前线程池中是否有没有释放的sqlsession对象
        SqlSession sqlSession = t1.get();
        if (sqlSession ==null){
            sqlSession = sqlSessionFactory.openSession();
            t1.set(sqlSession);
        }
        return sqlSession;
    }
    public  static  void commit(){
        //获取了当前线程中的SqlSession对象
        SqlSession sqlSession = openSession();
        sqlSession.commit();
        close();
    }
    public static void rollback(){
        SqlSession sqlSession = openSession();
        sqlSession.rollback();
        close();
    }
    public  static  void close(){
        SqlSession sqlSession = openSession();
        sqlSession.close();
    }
    public static <T> T getMapper(Class<T> mapper){
        SqlSession sqlSession = openSession();
        return sqlSession.getMapper(mapper);

    }

}

映射细节-resultmap使用

数据库中的列名和程序中的属性名不同时
image-20200616152754057

数据库中的列名和程序中的属性名不同时,因为MyBatis框架使用的是同名映射,所以我们之前的操作是给数据库中的列名起一个别名的方式来执行我们响应的sql语句

现在我们通过配置文件resultmap的方式能够完成高级映射,不仅不需要在sql语句中起别名还可以完成级联查询(多表参与的查询)

resultmap的代码实现

<mapper namespace="per.leiyu.dao.UserDao">
	<resultMap id="user_resultmap" type="User">
        <!-- 定义一些更加复杂的映射
            主键列,用标签 id定义
            其他列使用result定义

            column数据库中的列名
            property 在实体类中要对应的属性名
        -->
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="passward" property="passward"/>
        <result column="gender" property="gender"/>
        <result column="regist_time" property="registTime"/>
        
    </resultMap>
    <!-- 那么对应的我们的查询也就需要做一个改动 -->
    <!-- 将resultType改为了我们写好的resultMap
		另外因为已经使用了resultMap,就不需要再起别名就可以直接查询 -->
        <select id="queryUserByUsernameAndPassward" resultMap="user_resultmap">
        select id,username,passward,gender,regist_Time 
        from t_user
        where username=#{arg0} and passward=#{arg1}
    </select>
    
</mapper>

其实:如果使用resultmap只是为了实现简单的关系映射,那么是费事费力的,我们这里使用reslultmap的原因是:提醒在遇到简单的同名映射关系没办法实现其功能时,我们就使用resultmap的关系映射

另外resultmap的关系映射在关联关系中应用非常广泛

MyBatis处理关联关系-多表连接

实体间的关系:关联关系(拥有has 属于belong)

  • OneToOne:一对一(Passenger–Passport)
  • OneToMany:一对多(Employee-Department)
  • ManyToMany:多对多(Student-Subject)
Table建立外键关系
image-20200616155222273

一对一关联关系的处理案列

  • 创建数据库
  • 编写实体类
  • 创建Dao接口,写查询的方法
  • 编写关系映射文件
  • 测试类
  • 结果展示

创建数据库数据

CREATE TABLE t_passengers(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(50),
	sex VARCHAR(50),
	birthday DATE
)DEFAULT CHARSET = utf8;
CREATE TABLE t_passports(
	id INT PRIMARY KEY AUTO_INCREMENT,
	nationality VARCHAR(50),
	expire DATE,
	passenger_id INT UNIQUE,
	FOREIGN KEY (passenger_id) REFERENCES t_passengers(id)
)DEFAULT CHARSET =utf8;

INSERT INTO t_passengers VALUES(NULL,'leiyu_1','f','2019-11-11');
INSERT INTO t_passengers VALUES(NULL,'leiyu_2','m','2019-12-12');

INSERT INTO t_passports VALUES(NULL,'China','2050-11-11',1);
INSERT INTO t_passports VALUES(NULL,'America','2050-12-12',2);
数据库表建立完成
image-20200616161402994

开始编写实体类

package per.Dao;

import java.util.Date;

/**
 * @author 雷雨
 * @date 2020/6/16 16:05
 */
public class Passenger {

    private Integer id;
    private String name ;
    private String sex ;
    private Date birthday;

    //存储旅客的护照信息   :关系属性  对应着数据库中的数据
    private Passenger passenger;

    public Passenger() {
        super();
    }

    @Override
    public String toString() {
        return "Passenger{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", birthday=" + birthday +
                '}';
    }

    public Passenger(Integer id, String name, String sex, Date birthday) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.birthday = birthday;
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

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

    public Date getBirthday() {
        return birthday;
    }

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

package per.Dao;

import java.util.Date;

/**
 * @author 雷雨
 * @date 2020/6/16 16:08
 */
public class Passport {
    private Integer id;
    private String nationality;
    private Date expire;

    //护照存储了旅客的信息:关系属性
    private Passenger passenger;
    public Passport(Integer id, String nationality, Date expire) {
        this.id = id;
        this.nationality = nationality;
        this.expire = expire;
    }

    public Passport() {
        super();
    }

    @Override
    public String toString() {
        return "Passport{" +
                "id=" + id +
                ", nationality='" + nationality + '\'' +
                ", expire=" + expire +
                '}';
    }

    public Integer getId() {
        return id;
    }

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

    public String getNationality() {
        return nationality;
    }

    public void setNationality(String nationality) {
        this.nationality = nationality;
    }

    public Date getExpire() {
        return expire;
    }

    public void setExpire(Date expire) {
        this.expire = expire;
    }
}

创建Dao接口,写查询方法

PassengerDao.java

package per.Dao;

import org.apache.ibatis.annotations.Param;
import per.leiyu.Passenger;

/**
 * @author 雷雨
 * @date 2020/6/16 16:16
 */
public interface PassengerDao {
    //通过旅客的id查询旅客的信息和护照的信息    --->关联查询  级联查询
    Passenger queryPassengerById(@Param("id") Integer id);

}

编写关系映射文件

PassengerDaoMapper.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">
<!-- 指明该xml文件时用来描述那个dao接口的-->
<mapper namespace="per.Dao.PassengerDao">

    <resultMap id="Passenger_resultmap" type="Passenger">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="sex" property="sex"/>
        <result column="birthday" property="birthday"/>
        <association property="passport" javaType="Passport">
            <id column="PassId" property="id"/>
            <result column="nationality" property="nationality"/>
            <result column="expire" property="expire"/>

        </association>
    </resultMap>

    <select id="queryPassengerById" resultMap="Passenger_resultmap">
        select t_passengers.id,t_passengers.name,t_passengers.sex,t_passengers.birthday,
        t_passports.id passId,t_passports.nationality,t_passports.expire
        from t_passengers join t_passports
        on  t_passengers.id=t_passports.id
        where t_passengers.id=#{id}
    </select>

</mapper>
  • 要注意
    • property写的还是实体类中属性
    • javaType写的是该实体类对应了那个实体类(该关系属性对应了那个实体类)
  • 要注意中使用的是我们写好的resultmap
  • 最后要在mybatis-config.xml中把我们新写好的mapper映射文件注册使用

编写测试类(使用了我们之前写好的工具类)

使用了工具类代码量感觉瞬间减少了很多

package per.leiyu.UserDao;

import per.Dao.PassengerDao;
import per.leiyu.Passenger;
import per.util.MybatisUtil;

/**
 * @author 雷雨
 * @date 2020/6/16 16:31
 */
public class TesPassengerDao {
    public static void main(String[] args) {
        PassengerDao mapper = MybatisUtil.getMapper(PassengerDao.class);
        Passenger passenger = mapper.queryPassengerById(1);
        System.out.println(passenger);
        System.out.println(passenger.getPassport());;

    }
}

结果

通过mybatis多表关联查询结果
image-20200616164713245

一对一关联关系总结要注意的地方:

  1. 编写实体类的时候,要把关系属性也写入到实体类中
  2. 写关系映射文件Mapper.xml时,要注意使用的是reslutMap
  3. resultMap标签的子标签,也就是我们真正要定义的关系属性时使用的标签是association,并且在其中的column标签使用的是我们在sql语句给起的别名,而property标签表示的是其真正的在类中索引的属性名

一对多关联关系的处理案例

模拟员工和部门的一对多的关系

编写数据库代码

CREATE TABLE t_departments(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(50),
	location VARCHAR(100)
)DEFAULT CHARSET=utf8;
CREATE TABLE t_employees(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(50),
	salary DOUBLE,
	dept_id INT ,
	FOREIGN KEY (dept_id) REFERENCES t_departments(id)
)DEFAULT CHARSET= utf8;
INSERT INTO `t_departments` VALUES(1,"教学部","西安"),(2,"研发部","上海");
INSERT INTO `t_employees` VALUES(1,"leiyu01",10000.5,1),(2,"leiyu02",20000.5,1),(3,"xiaobai01",9000.5,2),(4,"xiaobai02",20001.5,2);
数据库表结果图展示
image-20200616202707369

开始编写实体类

  • 要注意:关系属性是一对多关系
package per.leiyu;

import java.util.List;

/**
 * @author 雷雨
 * @date 2020/6/16 20:28
 */
public class Department {
    private  Integer id;
    private String name ;
    private  String location;

    private List<Employee> employee;

    public Department(Integer id, String location, List<Employee> employee) {
        this.id = id;
        this.location = location;
        this.employee = employee;
    }

    public Department() {
        super();
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public List<Employee> getEmployee() {
        return employee;
    }

    public void setEmployee(List<Employee> employee) {
        this.employee = employee;
    }

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

package per.leiyu;

/**
 * @author 雷雨
 * @date 2020/6/16 20:29
 */
public class Employee {
    private Integer id;
    private String name;
    private Double salary;

    private Department department;

    public Employee(Integer id, String name, Double salary, Department department) {
        this.id = id;
        this.name = name;
        this.salary = salary;
        this.department = department;
    }

    public Employee() {
        super();
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Double getSalary() {
        return salary;
    }

    public void setSalary(Double salary) {
        this.salary = salary;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

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

创建Dao接口,写查询方法

package per.Dao;

import org.apache.ibatis.annotations.Param;
import per.leiyu.Department;

/**
 * @author 雷雨
 * @date 2020/6/16 20:32
 */
public interface  DepartmentDao {
    //根据id查询部门和属于该部门的员工
    Department queryDepartmentById(@Param("id") Integer id);

}

编写关系映射文件

<?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">
<!-- 指明该xml文件时用来描述那个dao接口的-->
<mapper namespace="per.Dao.DepartmentDao">



    <resultMap id="Deparment_resultmap" type="Department">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="location" property="location"/>
        <collection property="employee" ofType="Employee">
            <id column="emp_id" property="id"/>
            <result column="emp_name" property="name"/>
            <result column="salary" property="salary"/>
        </collection>
    </resultMap>

    <select id="queryDepartmentById" resultMap="Deparment_resultmap">
        select t_departments.id,t_departments.name,t_departments.location,t_employees.id emp_id,t_employees.name emp_name ,t_employees.salary
        from t_departments join t_employees
        on t_departments.id = t_employees.dept_id
        where t_departments.id=#{id}


    </select>


</mapper>
  • 注意在mapresult标签的子标签中因为我们的部门和员工是一对多的关系,且我们查询的是部门,所以选择的是collection标签
  • 如果我们要反着做(也就是根据员工查询员工的各项信息和他所属部门的信息),那么虽然在关系仍然是一对多,但是查询之后的结果(部门信息)只有一个,因此会选择assaciation标签

编写测试类

package per.leiyu.UserDao;


import per.Dao.DepartmentDao;
import per.leiyu.Department;
import per.util.MybatisUtil;

/**
 * @author 雷雨
 * @date 2020/6/16 20:46
 */
public class TestDepartment {
    public static void main(String[] args) {
        DepartmentDao mapper = MybatisUtil.getMapper(DepartmentDao.class);
        Department department = mapper.queryDepartmentById(1);
        System.out.println(department);
        System.out.println(department.getEmployee());
    }
}

查询结果

数据库查询结果
image-20200616205829146
我们程序查询的结果
image-20200616210303661

两者查询到的信息一致,说明我们的程序完成.

需要注意的:

  • 在映射文件的resultMap的字标签选择,要分析关系查询的结果是集合还是一个实体类的单个对象,选择合适的标签
  • 其他要注意的和在一对一查询中药注意的事项是一样的

多对多关联关系处理案例

多对多关联关系,我们这里用学生和课程来实现.

最终实现查询某一课程的信息和该课程下的所有学生的信息

多对多关联关系的关键是建立第三张表
image-20200616221302403

编写数据库代码

CREATE TABLE t_students(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(50),
	sex VARCHAR(1)
)DEFAULT CHARSET = utf8;
CREATE TABLE t_subjects(
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(50),
	grade INT 
)DEFAULT CHARSET = utf8;

CREATE TABLE t_stu_sub(
	student_id INT,
	subject_id INT ,
	FOREIGN KEY (student_id) REFERENCES t_students(id),
	FOREIGN KEY (subject_id) REFERENCES t_subjects(id),
	PRIMARY KEY (student_id,subject_id)
)DEFAULT CHARSET = utf8;
INSERT INTO t_students VALUES(1,"leiyu01",'m'),(2,"leiyu02",'f');
INSERT INTO t_subjects VALUES(1001,"JavaSE",1),(1002,"JavaEE",2);
INSERT INTO t_stu_sub VALUES(1,1001),(1,1002),(2,1001),(2,1002);

结果
image-20200616222851961

实体类

package per.leiyu;

import java.util.List;

/**
 * @author 雷雨
 * @date 2020/6/16 22:29
 */
public class Student {
    private Integer id;
    private String name;
    private String sex;

    private List<Subject> subject;

    public Student(Integer id, String name, String sex) {
        this.id = id;
        this.name = name;
        this.sex = sex;
    }

    public Student() {
        super();
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

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

    public List<Subject> getSubject() {
        return subject;
    }

    public void setSubject(List<Subject> subject) {
        this.subject = subject;
    }

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

package per.leiyu;

import java.util.List;

/**
 * @author 雷雨
 * @date 2020/6/16 22:30
 */
public class Subject {
    private Integer id;
    private String name;
    private Integer grade;

    private List<Student> student;

    public Subject(Integer id, String name, Integer grade) {
        this.id = id;
        this.name = name;
        this.grade = grade;
    }

    public Subject() {
        super();
    }

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public Integer getGrade() {
        return grade;
    }

    public void setGrade(Integer grade) {
        this.grade = grade;
    }

    public List<Student> getStudent() {
        return student;
    }

    public void setStudent(List<Student> student) {
        this.student = student;
    }

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

编写SubjectDao

package per.Dao;

import org.apache.ibatis.annotations.Param;
import per.leiyu.Subject;

/**
 * @author 雷雨
 * @date 2020/6/16 22:33
 */
public interface SubjectDao {
    Subject querySubjectById(@Param("id") Integer id);
}

编写文件映射

<?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">
<!-- 指明该xml文件时用来描述那个dao接口的-->
<mapper namespace="per.Dao.SubjectDao">

    <resultMap id="Subject_map" type="Subject">
        <id column="id" property="id"/>
        <result column="name" property="name"/>
        <result column="grade" property="grade"/>
        <collection property="student" ofType="Student">
            <id column="stu_id" property="id"/>
            <result column="stu_name" property="name"/>
            <result column="sex" property="sex"/>
        </collection>
    </resultMap>

    <select id="querySubjectById" resultMap="Subject_map">
        select t_subjects.id,t_subjects.name,t_subjects.grade,t_students.id stu_id,t_students.name stu_name,t_students.sex
        from t_subjects join t_stu_sub
        on t_subjects.id = t_stu_sub.subject_id
        join t_students
        on t_students.id = t_stu_sub.student_id
        where t_subjects.id=#{id}
    </select>

</mapper>

然后要在mybatis的配置文件中对我们写的mapper文件注册

编写测试类

package per.leiyu.UserDao;

import per.Dao.SubjectDao;
import per.leiyu.Subject;
import per.util.MybatisUtil;

/**
 * @author 雷雨
 * @date 2020/6/16 22:52
 */
public class TestSubjectDao {
    public static void main(String[] args) {
        SubjectDao mapper = MybatisUtil.getMapper(SubjectDao.class);
        Subject subject = mapper.querySubjectById(1001);
        System.out.println(subject);
        System.out.println(subject.getStudent());
    }
}

结果

程序的结果
image-20200616230300902
在数据库中查询的结果
image-20200616230427630

我是雷雨佳,一个普本科的学生,主要专注于Java后端和大数据开发

如果这篇文章有帮助到你,希望你给我一个大大的赞
如果有什么问题,希望你能留言和我一起研究,学习靠自觉,分享靠自愿

转载注明出处
https://blog.csdn.net/qq_40742223

猜你喜欢

转载自blog.csdn.net/qq_40742223/article/details/106798510