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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章