面对复杂的ER关系的情况
-
如有以下三个实体类
- 学员 User
- 课程 Course
- 教员 Teacher
-
其中这三者的关系如下ER图所示:
ER图 -
数据库表字段和关系图如下所示
数据库表字段及关系图 -
User 对象
package cn.lazyfennec.entity;
import java.util.List;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/4/12 22:03
*/
public class User {
private Integer id;
private String userName;
private String corp;
private List<Course> courses;
public User(Integer id, String userName, String corp) {
this.id = id;
this.userName = userName;
this.corp = corp;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getCorp() {
return corp;
}
public void setCorp(String corp) {
this.corp = corp;
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
- Course对象
package cn.lazyfennec.entity;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/4/12 22:04
*/
public class Course {
private int id;
private String courseName;
private Teacher teacher;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCourseName() {
return courseName;
}
public void setCourseName(String courseName) {
this.courseName = courseName;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
}
- Teacher对象
package cn.lazyfennec.entity;
/**
* @Author: Neco
* @Description:
* @Date: create in 2022/4/12 22:06
*/
public class Teacher {
private int id;
private String teacherName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTeacherName() {
return teacherName;
}
public void setTeacherName(String teacherName) {
this.teacherName = teacherName;
}
}
以上三个类有以下三种关系:
- 关联
- 容器
- 嵌套
为了解决如以上三个对象一样的复杂关系,我们需要用到ResultMap
ResultMap相关知识
- ResultMap 元素是MyBatis中最重要的最强大的元素。
- 数据库永远不是你想要的或需要它们是什么样的。
- ResultMap 可以实现复杂查询结果到复杂对象关联关系的转化。
- ResultMap的一些配置内容
-
Constructor
- 类在实例化时,用来注入结果到构造方法中
- idArg - ID参数;标记结果作为ID可以帮助提高整体性能效率。
- arg - 注入到构造方法的一个普通结果
- 例子:
<?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"> <mapper namespace="cn.lazyfennec.mapper.UserMapper"> <select id="getUserById" resultMap="UserMap" parameterType="int"> select id, userName, corp from user where id = #{id} </select> <resultMap type="cn.lazyfennec.entity.User" id="UserMap"> <constructor> <idArg column="id" javaType="Integer"/> <arg column="userName" javaType="String"/> <arg column="corp" javaType="String"/> </constructor> </resultMap> </mapper>
- 对应的java执行代码
package cn.lazyfennec; import cn.lazyfennec.entity.User; import cn.lazyfennec.mapper.UserMapper; import org.apache.ibatis.session.SqlSession; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; import java.io.InputStream; /** * @Author: Neco * @Description: * @Date: create in 2022/4/12 22:48 */ public class HelloMyBatis { public static void main(String[] args) { // 1.声明配置文件目录读取 String resource = "mybatis-conf.xml"; // 2.加载应用配置文件 InputStream inputStream = HelloMyBatis.class.getClassLoader().getResourceAsStream(resource); // 3.创建SqlSessionFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 4. 获取Session SqlSession sqlSession = sessionFactory.openSession(); try { // 5.获取操作类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 6. 完成查询操作 User user = userMapper.getUserById(9); System.out.println(user.getId() + " " + user.getUserName() + " " + user.getCorp()); } catch (Exception e) { e.printStackTrace(); } finally { // 7.关闭session if(sqlSession!=null) sqlSession.close(); } } }
- 类在实例化时,用来注入结果到构造方法中
-
Collection
- 实现一对多的关联
- id - 一个ID结果;标记结果作为ID可以帮助提高整体效能
- result - 注入到字段或 JavaBean 属性的普通结果
- Mapper.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"> <mapper namespace="cn.lazyfennec.mapper.UserMapper"> <select id="getUserById" resultMap="UserMap" parameterType="int"> select u.id, userName, corp, c.id courseId, c.courseName from user u left join usercourse uc on u.id = uc.user_id left join course c on uc.course_id = c.id where u.id = #{id} </select> <resultMap type="cn.lazyfennec.entity.User" id="UserMap"> <constructor> <idArg column="id" javaType="Integer"/> <arg column="userName" javaType="String"/> <arg column="corp" javaType="String"/> </constructor> <collection property="courses" ofType="cn.lazyfennec.entity.Course"> <id property="id" column="courseId"/> <result property="courseName" column="courseName"/> </collection> </resultMap> </mapper>
- 对应的Java代码
public static void main(String[] args) { // 1.声明配置文件目录读取 String resource = "mybatis-conf.xml"; // 2.加载应用配置文件 InputStream inputStream = HelloMyBatis.class.getClassLoader().getResourceAsStream(resource); // 3.创建SqlSessionFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 代码方式加载UserMapper Configuration configuration = sessionFactory.getConfiguration(); configuration.addMapper(UserMapper.class); // 4. 获取Session SqlSession sqlSession = sessionFactory.openSession(); try { // 5.获取操作类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 6. 完成查询操作 User user = userMapper.getUserByAnnotation(9); System.out.println(user.getId() + " " + user.getUserName() + " " + user.getCorp()); } catch (Exception e) { e.printStackTrace(); } finally { // 7.关闭session if(sqlSession!=null) sqlSession.close(); } }
- 实现一对多的关联
-
Association
- 实现复杂类型之间的关联
- id - 一个ID结果;标记结果作为ID可以帮助提高整体效能
- result - 注入到字段或 JavaBean 属性的普通结果
- Mapper.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"> <mapper namespace="cn.lazyfennec.mapper.UserMapper"> <select id="getUserById" resultMap="UserMap" parameterType="int"> select u.id, userName, corp, c.id courseId, c.courseName, t.id teacherId, t.teacherName from user u left join usercourse uc on u.id = uc.user_id left join course c on uc.course_id = c.id left join teacher t on c.teacher_id = t.id where u.id = #{id} </select> <resultMap type="cn.lazyfennec.entity.User" id="UserMap"> <constructor> <idArg column="id" javaType="Integer"/> <arg column="userName" javaType="String"/> <arg column="corp" javaType="String"/> </constructor> <collection property="courses" ofType="cn.lazyfennec.entity.Course"> <id property="id" column="courseId"/> <result property="courseName" column="courseName"/> <association property="teacher" column="teacher_id" javaType="cn.lazyfennec.entity.Teacher"> <id property="id" column="teacherId"/> <result property="teacherName" column="teacherName"/> </association> </collection> </resultMap> </mapper>
- 对应的Java代码
public static void main(String[] args) { // 1.声明配置文件目录读取 String resource = "mybatis-conf.xml"; // 2.加载应用配置文件 InputStream inputStream = HelloMyBatis.class.getClassLoader().getResourceAsStream(resource); // 3.创建SqlSessionFactory SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream); // 4. 获取Session SqlSession sqlSession = sessionFactory.openSession(); try { // 5.获取操作类 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); // 6. 完成查询操作 User user = userMapper.getUserById(9); System.out.println(user.getId() + " " + user.getUserName() + " " + user.getCorp()); System.out.println("courses: "); for (Course course : user.getCourses()) { System.out.println(">>> " + "id:" + course.getId() + " courseName:" + course.getCourseName() + " teacherId: " + course.getTeacher().getId() + " teacherName: " + course.getTeacher().getTeacherName()); } } catch (Exception e) { e.printStackTrace(); } finally { // 7.关闭session if (sqlSession != null) sqlSession.close(); } }
- 实现复杂类型之间的关联
-
数据库连接池 DataSource
- MyBatis 3.0 内置连接池
- dataSource type = POOLED 启用连接池
<dataSource type="POOLED">
MyBatis数据库连接声明周期
- 连接池常用配置选项
- poolMaximumActiveConnections
- 数据库最大活跃连接数
- 考虑到随着连接数的增加,性能可能会达到拐点,不建议设置过大
- poolMaximumIdleConnections
- 最大空闲连接数
- 建议设置与poolMaximum相同即可
- poolMaximumCheckoutTime
- 获取连接时如果没有idleConnection同时activeConnection也达到最大值,则从activeConnections列表第一个连接开始,检查是否超过poolMaximumCheckoutTime,如果超过,则强制使其失效,返回该连接。即使该连接断开,并返回到连接池中
- 由于SQL执行时间受服务器配置、表结构不通,建议设置为预期最大SQL执行时间。如2分钟,3分钟等,以提高获取数据库连接的效率。
- poolTimeToWait
- 获取服务器端数据库连接的超时时间,如果超过该时间,则打印日志,同时重新获取。
- 建议使用默认值20s
- poolPingEnabled
- 启用连接侦测,检查连接池中的连接是否为有效连接。
- 默认关闭,建议启用,防止服务器端异常关闭连接,导致客户端错误。
- poolPingQuery
- 侦测SQL,建议使用select 1,开销小
- poolPingConnectionsNotUsedFor
- 侦测时间,建议小于服务器超时时间,MySQL默认超时时间8小时(即服务器连接空闲超过八小时,服务器自动关闭该连接,但是如果不启用侦测,则客户端无法发现连接已经失效)
- poolMaximumActiveConnections
更多内容建议查看官网
点击右方链接查看官方文档:https://mybatis.org/mybatis-3/zh/index.html
网友评论