Mybatis的关系映射和相应的配置文件



一 关系映射
MyBatis 有两种不同的关联方式:l
嵌套查询:通过执行另外一个 SQL 映射语句来返回预期的复杂类型。
嵌套结果:使用嵌套结果映射来处理重复的联合结果的子集。


使用的标签:association、collection


1 一对一
人和身份证之间的一对一关系
1)表结构
CREATE TABLE `person` (
  `pid` int(11) NOT NULL,
  `pname` varchar(20) DEFAULT NULL,
  `cid` int(11) DEFAULT NULL,
  PRIMARY KEY (`pid`),
  KEY `cid` (`cid`),
  CONSTRAINT `person_ibfk_1` FOREIGN KEY (`cid`) REFERENCES `card` (`cid`)
)


CREATE TABLE `card` (
  `cid` int(11) NOT NULL,
  `cnum` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`cid`)
)


2)嵌套结果:
执行多表查询的sql语句
PersonMapper.xml
<resultMap type="Person" id="personMap">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>

<!-- 嵌套结果的设置方式 -->
<!-- 表示关联一个对象  resultMap表示关联的对象数据的resultMap值 -->
<association property="card" resultMap="com.rr.one2one.Card.cardMap"></association>

</resultMap>

<!-- 多表查询    必须使用resultMap -->
<select id="findById" parameterType="java.lang.Integer" resultMap="personMap">
select person.*,card.* 
from person 
inner join card 
on person.id=card.id 
where person.id=#{id}
</select>


CardMapper.xml
<resultMap type="Card" id="cardMap">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="num" column="num"/>

</resultMap>


3)嵌套查询:
会执行多条sql语句
PersonMapper.xml
<resultMap type="Person" id="personMap1">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>

<!-- 嵌套查询的设置方式 -->
<!-- 表示关联一个对象  
select 通过其他sql语句查询关联的数据,格式 namespace的值.sql的id
column 指定关联的查询中 关联的列 本例中column的值来自person表的字段
fetchType 设置懒加载 lazy 懒加载, eager非懒加载
-->
<association property="card" javaType="Card" column="cid" select="com.rr.one2one.Card.findByCId" fetchType="lazy"></association>

</resultMap>
<select id="findByPId" parameterType="java.lang.Integer" resultMap="personMap1">
select * 
from person  
where person.id=#{id}
</select>


CardMapper.xml
<resultMap type="Card" id="cardMap">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="num" column="num"/>

</resultMap>

<!-- person 嵌套查询时,select对应的sql,必须使用resultMap -->
<select id="findByCId" parameterType="int" resultMap="cardMap">
select * from card where card.id=#{id};
</select>


2 一对多/多对一
部门和员工之间关系
1)表结构
CREATE TABLE `t_dept` (
  `deptId` int(11) NOT NULL AUTO_INCREMENT,
  `deptName` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`deptId`)
)


CREATE TABLE `t_employee` (
  `empId` int(11) NOT NULL AUTO_INCREMENT,
  `empName` varchar(20) DEFAULT NULL,
  `salary` double DEFAULT NULL,
  `dept_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`empId`),
  KEY `FK_jgo5u3npdj1lborc1v50bsens` (`dept_id`),
  CONSTRAINT `FK_jgo5u3npdj1lborc1v50bsens` FOREIGN KEY (`dept_id`) REFERENCES `t_dept` (`deptId`)
)


2)嵌套结果:
DepartmentMapper.xml
<resultMap type="Department" id="deptMap">
<!-- 主键 -->
<id property="id" column="did"/>
<!-- 其他字段 -->
<result property="name" column="dname"/>

<!-- 嵌套结果的设置方式 
collention 表示集合关系
ofType  指定集合中对象的类型
javaType 指定存储数据的的集合的类型
-->
<collection property="emps" javaType="java.util.ArrayList" ofType="Employee" resultMap="com.rr.one2many.Employee.empMap"></collection>

</resultMap>


<!-- 多表查询    必须使用resultMap -->
<select id="findById" parameterType="int" resultMap="deptMap">
select d.id as did, d.name as dname,e.* 
from department d 
inner join employee e
on d.id=e.dept_id
where d.id=#{id};
</select>


其他操作:
<!-- 插入数据 -->
<insert id="add" parameterType="Department">

<!-- keyproperty的值 是实体类中的属性
order 有两个值,
BEFORE表示插入前获取值
AFTER表示插入后获取值,对于mysql,插入后获取值 -->
<selectKey keyProperty="id" resultType="int" order="AFTER">
<!-- LAST_INSERT_ID() 获取最后插入的值 ,将获取的值赋值给keyProperty指定的属性 -->
select LAST_INSERT_ID()
</selectKey>

insert into department(name) values(#{name});
</insert>

<!-- 如果是mysql,可以使用useGeneratedKeys="true"属性 -->
<insert id="addByGK" parameterType="Department" useGeneratedKeys="true" keyProperty="id">

insert into department(name) values(#{name});
</insert>

<!-- 得到表中的记录数,resultType 使用基本类型 -->
<select id="getCount" resultType="int">
select count(1) from department;
</select>


EmployeeMapper.xml
<resultMap type="Employee" id="empMap">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="birth" column="birth"/>
<!-- 嵌套结果 -->
<association property="dept" resultMap="com.rr.one2many.Department.deptMap"></association>

</resultMap>


3)嵌套查询:
DepartmentMapper.xml
<resultMap type="Department" id="deptMap1">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>

<!-- 嵌套查询的设置方式 
collention 表示集合关系
ofType  指定集合中对象的类型
javaType 指定存储数据的的集合的类型
-->
<collection property="emps" javaType="java.util.ArrayList" ofType="Employee" column="id" select="com.rr.one2many.Employee.findByDeptId"></collection>

</resultMap>


<select id="findByDId" parameterType="int" resultMap="deptMap1">
select * 
from department d
where d.id=#{id};
</select>


EmployeeMapper.xml
<resultMap type="Employee" id="empMap1">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>
<result property="age" column="age"/>
<result property="birth" column="birth"/>
<!-- 嵌套查询 -->
<association property="dept" column="dept_id" select="com.rr.one2many.Department.findByDId" fetchType="eager"></association>

</resultMap>
<select id="findByDeptId" parameterType="int" resultMap="empMap">
select * from employee where dept_id=#{id};
</select>

<select id="findAll" resultMap="empMap1">
select * from employee;
</select>


3 多对多
学生和课程之间的关系
1)表结构
CREATE TABLE `t_student` (
  `sid` int(11) NOT NULL AUTO_INCREMENT,
  `sname` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`sid`)
)
CREATE TABLE `t_course` (
  `cid` int(11) NOT NULL AUTO_INCREMENT,
  `cname` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`cid`)
)
CREATE TABLE `t_relation` (
  `sid` int(11) NOT NULL,
  `cid` int(11) NOT NULL,
  PRIMARY KEY (`sid`,`cid`),
  KEY `FK_ma6ynxw6eng27dnn2h242ec6g` (`sid`),
  CONSTRAINT `FK_fje0x78jps0jamjagtdc80r8d` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`),
  CONSTRAINT `FK_ma6ynxw6eng27dnn2h242ec6g` FOREIGN KEY (`cid`) REFERENCES `t_course` (`cid`)
)


2)嵌套结果
StudentMapper.xml
<resultMap type="Student" id="stuMap">
<!-- 主键 -->
<id property="id" column="stuid"/>
<!-- 其他字段 -->
<result property="name" column="stuname"/>

<!-- 嵌套结果的设置方式 
collention 表示集合关系
ofType  指定集合中对象的类型
javaType 指定存储数据的的集合的类型
-->
<collection property="courses" javaType="java.util.ArrayList" ofType="Course" resultMap="com.rr.many2many.Course.courseMap"></collection>

</resultMap>


<select id="findById" parameterType="int" resultMap="stuMap">
select s.id as stuid, s.name as stuname,c.id,c.name
from student s
inner join stu_course sc
on s.id=sc.sid
inner join course c
on c.id=sc.cid
where s.id=#{id};
</select>


CourseMapper.xml
<resultMap type="Course" id="courseMap">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>

<!-- 嵌套结果的设置方式 
collention 表示集合关系
ofType  指定集合中对象的类型
javaType 指定存储数据的的集合的类型
-->
<collection property="students" javaType="java.util.ArrayList" ofType="Student" resultMap="com.rr.many2many.Student.stuMap"></collection>

</resultMap>

<!-- 使用嵌套查询,传过来的是学生id -->
<select id="findByStuId" parameterType="int" resultMap="courseMap">
select c.*
from course c
inner join stu_course sc
on c.id=sc.cid
where sc.sid=#{id};
</select>


3)嵌套查询
StudentMapper.xml
<resultMap type="Student" id="stuMap1">
<!-- 主键 -->
<id property="id" column="id"/>
<!-- 其他字段 -->
<result property="name" column="name"/>

<!-- 嵌套查询的设置方式 -->
<collection property="courses" javaType="java.util.ArrayList" ofType="Course" column="id" select="com.rr.many2many.Course.findByStuId"></collection>

</resultMap>

<select id="findBySId" parameterType="int" resultMap="stuMap1">
select *
from student s
where s.id=#{id};
</select>


二 懒加载
映射文件中:fetchType="lazy"
主配置文件中:
<!-- 参数设置 -->
<settings>
    <!-- 启用懒加载,必须按照下面方式配置 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载即按需加载。必须写,且为false才会懒加载 -->  
<setting name="aggressiveLazyLoading" value="false"/>
</settings>


三 缓存


1 一级缓存
session级别的缓存
一级缓存是SqlSession级别的缓存。在操作数据库时需要构造 sqlSession对象,在对象中有一个(内存区域)数据结构(HashMap)用于存储缓存数据。不同的sqlSession之间的缓存数据区域(HashMap)是互相不影响的。
一级缓存的作用域是同一个SqlSession,在同一个sqlSession中两次执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。当一个sqlSession结束后该sqlSession中的一级缓存也就不存在了。Mybatis默认开启一级缓存。
如果没有启动事务,mybatis的一级缓存在spring中是没有作用的.


2 二级缓存
mapper级别的缓存
二级缓存是mapper级别的缓存,多个SqlSession去操作同一个Mapper的sql语句,多个SqlSession去操作数据库得到数据会存在二级缓存区域,多个SqlSession可以共用二级缓存,二级缓存是跨SqlSession的。
二级缓存是多个SqlSession共享的,其作用域是mapper的同一个namespace,不同的sqlSession两次执行相同namespace下的sql语句且向sql中传递参数也相同即最终执行相同的sql语句,第一次执行完毕会将数据库中查询的数据写到缓存(内存),第二次会从缓存中获取数据将不再从数据库查询,从而提高查询效率。Mybatis默认没有开启二级缓存需要在setting全局参数中配置开启二级缓存。


主配置文件:
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>


映射配置文件
<!-- 相关的映射启用二级缓存 -->
<!-- <cache /> -->

<!-- eviction 缓存策略
flushInterval 刷新间隔,单位毫秒
size 引用数目
readOnly 是否只读
-->
<cache 
eviction="FIFO"
flushInterval="10000"
size="1000"
readOnly="true"
></cache>
flushInterval:
刷新间隔,可以被设置为任意的正整数,单位毫秒。默认情况是不设置,也就是没有刷新间隔。
Size:
引用数目,可以被设置为任意正整数,缓存的对象数目和你运行环境的可用内存资源数目。默认值是1024。
readOnly:
是否只读,属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例,默认是false。
Eviction:
收回策略,
 LRU – 最近最少使用的:移除最长时间不被使用的对象。
FIFO – 先进先出:按对象进入缓存的顺序来移除它们。
SOFT – 软引用:移除基于垃圾回收器状态和软引用规则的对象。
WEAK – 弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。




四 SSM框架整合
1导入jar文件
导入spring、springmvc、mybatis、数据库驱动、数据库连接池的相关jar文件;
还需要导入mybatis-spring-1.2.1.jar


2 修改web.xml
引入spring、springmvc的核心配置
<!-- post提交方式中文乱码的处理 -->
  <filter>
  <filter-name>characterEncoding</filter-name>
  <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
  <init-param>
  <param-name>encoding</param-name>
  <param-value>utf8</param-value>
  </init-param>
  </filter>
  <filter-mapping>
  <filter-name>characterEncoding</filter-name>
  <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
    <!-- spring mvc 的核心配置 -->
  <servlet>
  <servlet-name>DispatchServlet</servlet-name>
  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  <!-- 指定加载哪个配置文件 -->
  <init-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:spring-mvc.xml</param-value>
  </init-param>
  <!-- tomcat服务器启动时,创建servlet对象 -->
  <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
  <servlet-name>DispatchServlet</servlet-name>
  <!-- 过滤任何资源,会造成静态资源不能访问 -->
  <url-pattern>/</url-pattern>
  </servlet-mapping>
  
  <!-- spring的核心配置 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <!-- classpath相当于/WEB-INF/classes -->
    <param-value>classpath:applicationContext.xml</param-value>
<!--     <param-value>/WEB-INF/classes/bean.xml</param-value> -->
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


3 spring mvc配置
<!-- 扫描注解 -->
  <context:component-scan base-package="com.rr.controller">
  <!-- 指定扫描哪些注解 -->
  <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>
   
  <mvc:annotation-driven>
  <!-- 处理json里的日期数据,默认日期被fastjson转为时间戳数据 -->
  <mvc:message-converters>  
            <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  
                <property name="objectMapper">  
                    <bean class="com.fasterxml.jackson.databind.ObjectMapper">  
                        <property name="dateFormat">  
                            <bean class="java.text.SimpleDateFormat">  
                                <constructor-arg type="java.lang.String" value="yyyy-MM-dd HH:mm:ss" />  
                            </bean>  
                        </property>  
                    </bean>  
                </property>  
            </bean>  
        </mvc:message-converters>
  </mvc:annotation-driven>
   
  
  <mvc:resources location="/js/" mapping="/js/**"></mvc:resources>
   
<!-- 视图解析器 -->
   <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <!-- 前缀 -->
    <property name="prefix" value="/"></property>
    <!-- 后缀 -->
    <property name="suffix" value=".jsp"></property>
   
   </bean>


4 spring配置
<!-- 扫描注解 -->
  <context:component-scan base-package="com.rr">
  <!-- 扫描时,排除指定的注解 -->
  <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
  </context:component-scan>
   
   
   <!-- 数据源的配置 -->
  <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
  <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
  <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/hib"></property>
  <property name="user" value="root"></property>
  <property name="password" value="root"></property>
  <property name="initialPoolSize" value="5"></property>
  <property name="maxPoolSize" value="10"></property>
  <property name="maxIdleTime" value="1000"></property>
  </bean>
   
   <!-- 创建mybatis的会话工厂对象 -->
   <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 设置数据源 -->
<property name="dataSource" ref="dataSource"></property>
<!-- 加载mybatis主配置文件 -->
<property name="configLocation" value="classpath:mybatis.xml"/>
<!-- 加载映射文件 -->
<property name="mapperLocations" value="classpath:com/rr/mapper/*.xml"/>

   </bean>
   
   <!-- 扫描映射代理的接口类,注入到spring容器中 -->
   <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
    <property name="basePackage" value="com.rr.dao"></property>
   </bean>
   
    <!-- 1配置事务管理类 -->
    <bean id="txManage" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   
    <property name="dataSource" ref="dataSource"></property>
    </bean>
   
    <!-- 2配置事务的特性 -->
   <tx:advice id="txAdvice" transaction-manager="txManage">
    <tx:attributes>
   
    <tx:method name="*" read-only="false"/>
   
    </tx:attributes>
   </tx:advice>
   
   <!-- 3AOP配置 -->
   <aop:config>
    <!-- 切入点 -->
    <aop:pointcut expression="execution(* com.rr.service.impl.*.*(..))" id="pc"/>
   
    <!-- 通知 -->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="pc"/>
   
   </aop:config>


5 mybatis配置
<configuration>



<!-- 参数设置 -->
<settings>
    <!-- 启用懒加载,必须按照下面方式配置 -->
<setting name="lazyLoadingEnabled" value="true"/>
<setting name="aggressiveLazyLoading" value="false"/>

<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>

<typeAliases>

<typeAlias type="com.rr.entity.Department" alias="Department"/>
<typeAlias type="com.rr.entity.Employee" alias="Employee"/>

</typeAliases>


<mappers>

</mappers>
</configuration>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值