由于我们基础的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);
}
}
数据库中的列名和程序中的属性名不同时 |
---|
数据库中的列名和程序中的属性名不同时,因为MyBatis框架使用的是同名映射,所以我们之前的操作是给数据库中的列名起一个别名的方式来执行我们响应的sql语句
现在我们通过配置文件resultmap
的方式能够完成高级映射
,不仅不需要在sql语句中起别名还可以完成级联查询(多表参与的查询)
<mapper namespace="per.leiyu.dao.UserDao">
<resultMap id="user_resultmap" type="User">
<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>
<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的关系映射在关联关系中应用非常广泛
实体间的关系:关联关系(拥有has 属于belong)
- OneToOne:一对一(Passenger–Passport)
- OneToMany:一对多(Employee-Department)
- ManyToMany:多对多(Student-Subject)
Table建立外键关系 |
---|
创建数据库数据
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);
数据库表建立完成 |
---|
开始编写实体类
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编写对象关系映射文件
<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>
编写测试类(使用了我们之前写好的工具类)
使用了工具类代码量感觉瞬间减少了很多
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多表关联查询结果 |
---|
一对一关联关系总结要注意的地方:
- 编写实体类的时候,要把
关系属性
也写入到实体类中- 写关系映射文件Mapper.xml时,要注意使用的是
reslutMap
- 在
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);
数据库表结果图展示 |
---|
开始编写实体类
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);
}
编写关系映射文件
<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>
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());
}
}
查询结果
数据库查询结果 |
---|
我们程序查询的结果 |
---|
两者查询到的信息一致,说明我们的程序完成.
需要注意的:
resultMap
的字标签选择,要分析关系查询的结果是集合还是一个实体类的单个对象,选择合适的标签多对多关联关系,我们这里用学生和课程来实现.
最终实现查询某一课程的信息和该课程下的所有学生的信息
多对多关联关系的关键是建立第三张表 |
---|
编写数据库代码
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);
结果 |
---|
实体类
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);
}
编写文件映射
<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());
}
}
结果
程序的结果 |
---|
在数据库中查询的结果 |
---|
我是雷雨佳,一个
普本科
的学生,主要专注于Java后端和大数据开发
如果这篇文章有帮助到你,希望你给我一个
大大的赞
如果有什么问题,希望你能留言
和我一起研究
,学习靠自觉,分享靠自愿
转载注明出处
https://blog.csdn.net/qq_40742223