#MyBatis进阶
- 复杂Java对象与多张数据库表之间的映射关系
- 配置数据库连接池提高MyBatis对后端数据库访问的性能 ##更为复杂的E-R图 学员对课程是多对多关系,而教员与课程是一对多关系
- 
- 学员 User
 
- 
- 课程 Couser
 
- 
- 教员 Author
 
以上实体对应的关系图如下:
以上关系对应的数据库表关系如下:
各个实体都具有对应的属性,但是由于User与Cousre是多对多关系,则我们还需要一个多对多关系表UserCourse,来保存User与Course的关系。由于Teacher与Course是一对多的关系,则我们在Course中添加Teacher的唯一标示。
##复杂对象关系
- Java对象
- 
- 关联
 
 
- 关联
- 
- 容器
 
- 
- 嵌套
 
 
- 嵌套
##ResultMap 复杂Java关系映射解决,帮助我们复杂对象到多张数据库表的转换。
- ResultMap元素师MyBatis中最重要最强大的元素。
- 数据库永远不是你想要的或需要它们是什么样的。
- ResultMap可以实现复杂查询结果到复杂对象关联关系的转化。
##Constructor 通过构造方法的方式,对对象进行赋值建立映射关系,这种方法一般用于处理关联时,使用。
- 类在实例化时,用对象的构造函数注入到对象中:
- 
- idArg - ID参数;标记结果作为ID可以帮助提高整体效能
 
- 
- arg - 注入到构造方法的一个普通结果
 
##ResultMap通过构造函数实例 ###定义了MyBatis-conf.xml的SqlSessionFactory的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <environments default="development">
        <environment id="development">
            <!-- 事务管理 -->
            <transactionManager type="jdbc">
                <!--<property name="..." value="..."/>-->
            </transactionManager>
            <!-- 数据库连接数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.1.200/cloud_study"/>
                <property name="username" value="root"/>
                <property name="password" value="dVHJtG0T:pf*"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="com/hava/cloud_study/repository/userMapper.xml" />
    </mappers>
</configuration>
###声明Java对象 ####User
public class User {
    private int id;
    private String userName;
    private String corp;
    private List<Course> courses;
    ...
    //Getter and Setter
}
####Course
public class Course {
    private int id;
    private String courseName;
    private Teacher teacher;
    ...
    //Getter and Setter
}
####Teacher
public class Teacher {
    private int id;
    private String teacherName;
    ...
    //Getter and Setter
}
###UserOp接口 我们通过获取用户的方式,来获取三张数据库表之间的连接查询,并建立三个对象之间的连接关系。
package com.hava.cloud_study.repository;
import com.hava.cloud_study.entity.User;
/**
 * Created by zhanpeng on 09/10/2016.
 */
public interface UserOp {
    public User getUser(int id);
}
###resultMap核心Mapper 在Mapper文件中添加resultMap的标签属性,id在所表示的这个resultMap将会被用在增持该查中设置中。type表示为要转换的对象结果。constructor标签下面表示的是该类的属性(非连接关系的属性),idArg表示为行记录的唯一id,arg表示一般属性。column必须和对象的属性名称相一致。javaType对应的Java的数据类型。
<?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="com.hava.cloud_study.repository.UserOp">
    <select id="getUser" parameterType="int" resultMap="UserMap">
        select u.id
        as userId,userName,courseName,corp,c.id as courseId,teacher.id as
        teacherId,teacherName from user u left
        join
        UserCourse uc on u.id
        =uc.user_id left join course c on c.id =
        uc.course_id left join teacher
        on teacher.id = c.teacher_id where u.id
        = #{id}
    </select>
    <resultMap id="UserMap"
               type="com.hava.cloud_study.entity.User">
        <constructor>
            <idArg column="userId" javaType="int" />
            <arg column="userName" javaType="String" />
            <arg column="corp" javaType="String" />
        </constructor>
        <collection property="courses"
                    ofType="com.hava.cloud_study.entity.Course">
            <id property="id" column="courseId" />
            <result property="courseName" column="courseName" />
            <association property="teacher" column="teacher_id"
                         javaType="com.hava.cloud_study.entity.Teacher">
                <id property="id" column="teacherId" />
                <result property="teacherName" column="teacherName" />
            </association>
        </collection>
    </resultMap>
</mapper>
必须在User中加入构造函数,构造函数的属性必须和constructor一致。
###执行
package com.hava.cloud_study.service;
import java.io.InputStream;
import com.hava.cloud_study.entity.User;
import com.hava.cloud_study.repository.UserOp;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
public class HelloMyBatis {
    public static void main(String[] args) {
        // 1. 声明配置⽂件的⺫录渎职
        String resource = "mybatis-conf.xml";
        // 2. 加载应⽤配置⽂件
        InputStream is = HelloMyBatis.class.getClassLoader()
                .getResourceAsStream(resource);
        // 3. 创建SqlSessonFactory
        SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder()
                .build(is);
        // 4. 获取Session
        SqlSession session = sessionFactory.openSession();
        try {
            // 5. 获取操作类
            UserOp userOp = session.getMapper(UserOp.class);
            // 6. 完成查询操作
            User user = userOp.getUser(25);
            System.out.println(user.getId() + " " + user.getUserName() + " ");
                    System.out.println(user.getCourses().get(0).getCourseName() +" ");
            System.out.println(user.getCourses().get(0).getTeacher().getTeacherName());
        } finally {
            // 7.关闭Session
            session.close();
        }
    }
}
###执行结果
25 ZhanPeng 
Java 
OldTeacher
##Collection 容器 User当中的List注入,也是通过resultMap,通过collection的标签来实现。
- 实现一对多的关联
- 
- id - 一个ID结果;标记结果作为ID可以帮助提高整体效能
 
- 
- result - 注入到字段或者JavaBean属性的普通结果 - 普通属性注入
 
Collection 标签中property必须和对象的属性一致。
<?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="com.hava.cloud_study.repository.UserOp">
    <select id="getUser" parameterType="int" resultMap="UserMap">
        select u.id
        as userId,userName,courseName,corp,c.id as courseId,teacher.id as
        teacherId,teacherName from user u left
        join
        UserCourse uc on u.id
        =uc.user_id left join course c on c.id =
        uc.course_id left join teacher
        on teacher.id = c.teacher_id where u.id
        = #{id}
    </select>
    <resultMap id="UserMap"
               type="com.hava.cloud_study.entity.User">
        <constructor>
            <idArg column="userId" javaType="int" />
            <arg column="userName" javaType="String" />
            <arg column="corp" javaType="String" />
        </constructor>
        <!-- 定义对象为List的属性 -->
        <collection property="courses"
                    ofType="com.hava.cloud_study.entity.Course">
            <id property="id" column="courseId" />
            <result property="courseName" column="courseName" />
            <association property="teacher" column="teacher_id"
                         javaType="com.hava.cloud_study.entity.Teacher">
                <id property="id" column="teacherId" />
                <result property="teacherName" column="teacherName" />
            </association>
        </collection>
    </resultMap>
</mapper>
##Association 实现对象与对象之间的连接
- 实现复杂类型之间的关联
- 
- id - 一个ID结果;标记结果作为ID可以帮助提高整体效能
 
- 
- result - 注入到字段或者JavaBean属性的普通结果 - 普通属性注入
 
<?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="com.hava.cloud_study.repository.UserOp">
    <select id="getUser" parameterType="int" resultMap="UserMap">
        select u.id
        as userId,userName,courseName,corp,c.id as courseId,teacher.id as
        teacherId,teacherName from user u left
        join
        UserCourse uc on u.id
        =uc.user_id left join course c on c.id =
        uc.course_id left join teacher
        on teacher.id = c.teacher_id where u.id
        = #{id}
    </select>
    <resultMap id="UserMap"
               type="com.hava.cloud_study.entity.User">
        <constructor>
            <idArg column="userId" javaType="int" />
            <arg column="userName" javaType="String" />
            <arg column="corp" javaType="String" />
        </constructor>
        <!-- 定义对象为List的属性 -->
        <collection property="courses"
                    ofType="com.hava.cloud_study.entity.Course">
            <id property="id" column="courseId" />
            <result property="courseName" column="courseName" />
            <!-- 一对一 -->
            <association property="teacher" column="teacher_id"
                         javaType="com.hava.cloud_study.entity.Teacher">
                <id property="id" column="teacherId" />
                <result property="teacherName" column="teacherName" />
            </association>
        </collection>
    </resultMap>
</mapper>
#MyBatis数据库连接池 ##DataSource
- MyBatis 3.0 内置数据库连接池
- dataSource type="POOLED"启动连接池
<!-- 数据库连接数据源 -->
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://192.168.1.200/cloud_study"/>
                <property name="username" value="root"/>
                <property name="password" value="dVHJtG0T:pf*"/>
            </dataSource>
        </environment>
##数据库连接生命周期 MyBatis数据库连接池的内部实现,与之前的DBCP连接池是非常类似的。MyBatis数据库连接池实际上维护了一个空闲连接链和活跃连接链两个队列,当MyBatis要实际执行SQL时,获取一个数据库连接,首先回去判断空闲的队列中是否有空闲的数据库连接,如果有返回数据库连接去执行SQL,如果没有,则判断当前活跃的数据库连接是否已经满,如果没有超过则创建新连接并加入到活跃列表中。如果已满或者超过则回去检查活跃连接队列中,最早的连接是否过期,如果过期则移除数据库连接。在创建新的数据库连接

##连接池常用配置选项
- 
poolMaximumActiveConnections 
- 
- 数据库最大活跃连接数
 
- 
- 考虑到随着连接数的增加,性能可能达到拐点,不建议设置过大。
 
- 
poolMaximumIdleConnections 
- 
- 最大空闲连接数
 
- 
- 经验值建议设置与poolMaximum相同即可
 
- 
poolMaximumCheckoutTime 
- 
- 获取连接时如果没有idleConnection同时activeConnection达到最大值,则从activeConnections列表第一个连接开始,检查是否超过poolMaximumCheckoutTime,如果超过,则强制使其失效,返回该连接。
 
- 
- 由于SQL执行时间受服务器配置、表结构不同,建议设置为预期最大SQL执行时间。
 
- 
poolTimeToWait 
- 
- 获取服务器端数据库连接的超时时间,如果超过该时间,则打印日志,同时重新获取。
 
- 
- 建议使用默认值20s
 
- 
poolPingEnabled 
- 
- 启动连接侦测,检查连接池中的连接是否为有效连接
 
- 
- 默认关闭,建议启动,防止服务器端异常关闭,导致客户端错误
 
- 
poolPingQuery 
- 
- 侦测SQL,建议使用select 1开销较小
 
- 侦测SQL,建议使用
- 
poolPingConnectionsNotUsedFor 
- 
- 侦测时间,建议小于服务器端超时时间,MySQL默认超时8小时
 
来源:oschina
链接:https://my.oschina.net/u/52678/blog/755829

