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